日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

数据结构--散列表 Hash Table

發(fā)布時(shí)間:2024/7/5 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据结构--散列表 Hash Table 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

    • 1.線性探測(cè) 哈希表代碼
    • 2.拉鏈法 哈希表代碼

  • 1. 散列表用的是數(shù)組支持按照下標(biāo)隨機(jī)訪問(wèn)數(shù)據(jù)的特性,所以散列表其實(shí)就是數(shù)組的一種擴(kuò)展,由數(shù)組演化而來(lái)。可以說(shuō),如果沒(méi)有數(shù)組,就沒(méi)有散列表。
  • 2. 散列函數(shù),設(shè)計(jì)的基本要求
  • 散列函數(shù)計(jì)算得到的散列值是一個(gè)非負(fù)整數(shù)( 因?yàn)閿?shù)組下標(biāo)從0開(kāi)始)
  • 如果 key1 = key2,那 hash(key1)== hash(key2)
  • 如果 key1 != key2,那 hash(key1)!= hash(key2)
  • 第3條是很難完全滿(mǎn)足的,不滿(mǎn)足稱(chēng)之,散列沖突

    • 3. 散列沖突 解決方法:
  • 開(kāi)放尋址法
    a.線性探測(cè)



    線性探測(cè)法,當(dāng)空閑位置越來(lái)越少時(shí),幾乎要遍歷整個(gè)散列表,接近O(n)復(fù)雜度
    b. 二次探測(cè):每次的步長(zhǎng)是 1, 2, 4, 8, 16,…
    c. 雙重散列:使用多個(gè)散列函數(shù),先用第一個(gè),如果位置被占,再用第二個(gè)散列函數(shù)。。。直到找到空閑位置
    不管哪種方法,空閑位置不多了,沖突概率會(huì)大大提高,盡量保證有一定比例的空閑(用裝載因子表示,因子越大,空位越少,沖突越多,散列表性能下降)
  • 鏈表法(更常用的解決沖突的辦法)
    • 4. 如何設(shè)計(jì)散列函數(shù)
      a. 散列函數(shù)的設(shè)計(jì)不能太復(fù)雜。過(guò)于復(fù)雜的散列函數(shù),勢(shì)必會(huì)消耗很多計(jì)算時(shí)間,也就間接的影響到散列表的性能。
      b. 散列函數(shù)生成的值要盡可能隨機(jī)并且均勻分布,這樣才能避免或者最小化散列沖突,即便出現(xiàn)沖突,散列到每個(gè)槽里的數(shù)據(jù)也會(huì)比較平均,不會(huì)出現(xiàn)某個(gè)槽內(nèi)數(shù)據(jù)特別多的情況。
      c. 裝載因子超過(guò)閾值,自動(dòng)擴(kuò)容,避免累積到最后一次性搬移數(shù)據(jù),分批多次搬移,O(1)復(fù)雜度
      d. 數(shù)據(jù)量比較小,裝載因子小的時(shí)候,適合采用開(kāi)放尋址法
      e. 基于鏈表的散列沖突處理方法比較適合存儲(chǔ)大對(duì)象、大數(shù)據(jù)量的散列表,而且,比起開(kāi)放尋址法,它更加靈活,支持更多的優(yōu)化策略,比如用紅黑樹(shù)代替鏈表。

    1.線性探測(cè) 哈希表代碼

    hashtable1.h

    /*** @description: 哈希表,開(kāi)放尋址--線性探測(cè)法* @author: michael ming* @date: 2019/5/6 10:26* @modified by: */ #ifndef SEARCH_HASHTABLE1_H #define SEARCH_HASHTABLE1_H #include <iostream> enum KindOfItem {Empty, Active, Deleted}; template <class DataType> struct HashItem {DataType data;KindOfItem info;HashItem<DataType>(KindOfItem i = Empty):info(i){}HashItem<DataType>(const DataType &d, KindOfItem i = Empty):data(d), info(i){}int operator== (HashItem<DataType> &a){return data == a.data;}int operator!= (HashItem<DataType> &a){return data != a.data;} }; template <class DataType> class hashtable1 { private:HashItem<DataType> *ht; //散列表數(shù)組int TableSize; //散列表長(zhǎng)度int currentSize; //當(dāng)前表項(xiàng)個(gè)數(shù)int deletedSize; //刪除標(biāo)記的元素個(gè)數(shù) public:hashtable1<DataType>(int m){TableSize = m;ht = new HashItem<DataType> [TableSize];currentSize = 0;deletedSize = 0;}~hashtable1<DataType>(){delete [] ht;}int hash(const DataType &newData) const{return newData%TableSize; //留余數(shù)法}int find(const DataType &x) const;int find_de(const DataType &x) const; //當(dāng)有deleted標(biāo)記的元素時(shí),插入函數(shù)調(diào)用此查找int insert(const DataType &x);int delete_elem(const DataType &x);void print() const{for(int i = 0; i < TableSize; ++i){std::cout << ht[i].data << " " << ht[i].info << "->";}std::cout << std::endl;}int isInTable(const DataType &x){int i = find(x);return i >= 0 ? i : -1;}DataType getValue(int i) const{return ht[i].data;} }; #endif //SEARCH_HASHTABLE1_H

    hashtable1.cpp

    /*** @description: 哈希表,開(kāi)放尋址--線性探測(cè)法* @author: michael ming* @date: 2019/5/6 10:26* @modified by: */ #include "hashtable1.h" template <class DataType> int hashtable1<DataType>::find(const DataType &x) const {int i = hash(x);int j = i;while(ht[j].info == Deleted || (ht[j].info == Active && ht[j].data != x)) //說(shuō)明存在沖突{j = (j+1)%TableSize; //用解決沖突的方法繼續(xù)查找(開(kāi)放定址法)if(j == i)return -TableSize; //遍歷整個(gè)散列表,未找到}if(ht[j].info == Active)return j; //找到,返回正值elsereturn -j; //沒(méi)找到,返回負(fù)值 } template <class DataType> int hashtable1<DataType>::find_de(const DataType &x) const //當(dāng)有deleted標(biāo)記的元素時(shí),插入函數(shù)調(diào)用此查找 {int i = hash(x);int j = i;while(ht[j].info == Active) //說(shuō)明存在沖突{j = (j+1)%TableSize; //用解決沖突的方法繼續(xù)查找(開(kāi)放定址法)if(j == i)return -TableSize; //遍歷整個(gè)散列表,沒(méi)有空位}return j; //返回標(biāo)記為Empty或者Deleted的位置 } template <class DataType> int hashtable1<DataType>::insert(const DataType &x) {int i = find(x);if(i > 0)return 0; //元素x已存在else if(i != -TableSize && !deletedSize) //元素x不存在,且散列表未滿(mǎn)(且沒(méi)有deleted標(biāo)記){ht[-i].data = x; //元素賦值ht[-i].info = Active; //占用了,標(biāo)記一下currentSize++;return 1;}else if(i != -TableSize && deletedSize) //元素x不存在,且散列表未滿(mǎn)(且有deleted標(biāo)記){int j = find_de(x);if(j >= 0){if(ht[j].info == Deleted)deletedSize--;ht[j].data = x; //元素賦值ht[j].info = Active; //占用了,標(biāo)記一下(刪除標(biāo)記改成占用標(biāo)記 )currentSize++;return 1;}elsereturn 0;}else return 0; } template <class DataType> int hashtable1<DataType>::delete_elem(const DataType &x) {int i = find(x);if(i >= 0){ht[i].info = Deleted; //找到了要?jiǎng)h除的,標(biāo)記刪除currentSize--;deletedSize++;return 1;}else return 0; }

    hashtable1_test.cpp 測(cè)試程序

    /*** @description: * @author: michael ming* @date: 2019/5/6 10:42* @modified by: */ #include "hashtable1.cpp" #include <iostream> int main() {hashtable1<int> ht1(10);ht1.print();for(int i = 15; i < 18; ++i){ht1.insert(i);ht1.print();}for(int i = 25; i < 29; ++i){ht1.insert(i);ht1.print();}for(int i = 27; i < 29; ++i){ht1.delete_elem(i);ht1.print();}for(int i = 100; i < 103; ++i){ht1.insert(i);ht1.print();}for(int i = 200; i < 203; ++i){ht1.insert(i);ht1.print();}if(ht1.isInTable(109) >= 0)std::cout << ht1.getValue(ht1.isInTable(109));return 0; }

    測(cè)試結(jié)果:(data,標(biāo)記位)標(biāo)記 empty = 0,active = 1, deleted = 2

    2.拉鏈法 哈希表代碼

    linkedHash.h

    /*** @description: 拉鏈法散列表* @author: michael ming* @date: 2019/5/6 17:56* @modified by: */#ifndef SEARCH_LINKEDHASH_H #define SEARCH_LINKEDHASH_H #include <iostream> template <class DataType> struct linkedNode //鏈表節(jié)點(diǎn) {DataType data;linkedNode *next;linkedNode():next(NULL){}linkedNode(const DataType &d):next(NULL), data(d){} }; template <class DataType> class linkedList //鏈表 { public:linkedNode<DataType> *head;linkedList(){head = new linkedNode<DataType>(); //表頭哨兵}~linkedList(){delete head;} }; template <class DataType> class linkedHash { private:linkedList<DataType> *htList; //散列表鏈表數(shù)組int bucket; //散列表桶個(gè)數(shù) public:linkedHash<DataType>(int m):bucket(m){htList = new linkedList<DataType> [bucket] ();}~linkedHash<DataType>(){for(int i = 0; i < bucket; ++i){linkedNode<DataType> *p = htList[i].head->next, *q = p;while(q != NULL){p = q;q = q->next;delete p;}}delete [] htList;}int hash(const DataType &newData) const{return newData%bucket; //留余數(shù)法}linkedNode<DataType>* find(const DataType &x) const{int i = hash(x);linkedNode<DataType> *p = htList[i].head->next, *q = htList[i].head;while(p && p->data != x){q = p;p = p->next;}return q; //返回找到元素的前一個(gè)節(jié)點(diǎn),或者沒(méi)有找到,返回最后一個(gè)元素}linkedNode<DataType>* insert(const DataType &x){int i = hash(x);linkedNode<DataType> *p = htList[i].head, *q = p;while(q != NULL){p = q;q = q->next;}p->next = new linkedNode<DataType>(x);return p->next;}void delete_elem(const DataType &x){linkedNode<DataType> *q = find(x), *p;if(q->next){p = q->next;q->next = q->next->next;delete p;}}void print() const{for(int i = 0; i < bucket; ++i){std::cout << i << "[ ]";linkedNode<DataType> *p = htList[i].head->next;while(p){std::cout << p->data << "->";p = p->next;}std::cout << std::endl;}std::cout << "----------------------" << std::endl;} }; #endif //SEARCH_LINKEDHASH_H

    linkedHash_test.cpp 測(cè)試程序

    /*** @description: 拉鏈法散列表 測(cè)試* @author: michael ming* @date: 2019/5/6 17:57* @modified by: */ #include "linkedHash.h" int main() {linkedHash<int> ht2(10);for(int i = 15; i < 37; ++i){ht2.insert(i);ht2.print();}ht2.delete_elem(15);ht2.print();ht2.delete_elem(18);ht2.print();ht2.delete_elem(28);ht2.print();ht2.insert(88);ht2.print();ht2.delete_elem(100);ht2.print();return 0; }

    測(cè)試結(jié)果:

    總結(jié)

    以上是生活随笔為你收集整理的数据结构--散列表 Hash Table的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。