数据结构--散列表 Hash Table
生活随笔
收集整理的這篇文章主要介紹了
数据结构--散列表 Hash Table
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 1.線性探測 哈希表代碼
- 2.拉鏈法 哈希表代碼
- 1. 散列表用的是數組支持按照下標隨機訪問數據的特性,所以散列表其實就是數組的一種擴展,由數組演化而來。可以說,如果沒有數組,就沒有散列表。
- 2. 散列函數,設計的基本要求
第3條是很難完全滿足的,不滿足稱之,散列沖突。
- 3. 散列沖突 解決方法:
a.線性探測
線性探測法,當空閑位置越來越少時,幾乎要遍歷整個散列表,接近O(n)復雜度
b. 二次探測:每次的步長是 1, 2, 4, 8, 16,…
c. 雙重散列:使用多個散列函數,先用第一個,如果位置被占,再用第二個散列函數。。。直到找到空閑位置
不管哪種方法,空閑位置不多了,沖突概率會大大提高,盡量保證有一定比例的空閑(用裝載因子表示,因子越大,空位越少,沖突越多,散列表性能下降)
- 4. 如何設計散列函數
a. 散列函數的設計不能太復雜。過于復雜的散列函數,勢必會消耗很多計算時間,也就間接的影響到散列表的性能。
b. 散列函數生成的值要盡可能隨機并且均勻分布,這樣才能避免或者最小化散列沖突,即便出現沖突,散列到每個槽里的數據也會比較平均,不會出現某個槽內數據特別多的情況。
c. 裝載因子超過閾值,自動擴容,避免累積到最后一次性搬移數據,分批多次搬移,O(1)復雜度
d. 數據量比較小,裝載因子小的時候,適合采用開放尋址法
e. 基于鏈表的散列沖突處理方法比較適合存儲大對象、大數據量的散列表,而且,比起開放尋址法,它更加靈活,支持更多的優化策略,比如用紅黑樹代替鏈表。
1.線性探測 哈希表代碼
hashtable1.h
/*** @description: 哈希表,開放尋址--線性探測法* @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; //散列表數組int TableSize; //散列表長度int currentSize; //當前表項個數int deletedSize; //刪除標記的元素個數 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; //留余數法}int find(const DataType &x) const;int find_de(const DataType &x) const; //當有deleted標記的元素時,插入函數調用此查找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_Hhashtable1.cpp
/*** @description: 哈希表,開放尋址--線性探測法* @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)) //說明存在沖突{j = (j+1)%TableSize; //用解決沖突的方法繼續查找(開放定址法)if(j == i)return -TableSize; //遍歷整個散列表,未找到}if(ht[j].info == Active)return j; //找到,返回正值elsereturn -j; //沒找到,返回負值 } template <class DataType> int hashtable1<DataType>::find_de(const DataType &x) const //當有deleted標記的元素時,插入函數調用此查找 {int i = hash(x);int j = i;while(ht[j].info == Active) //說明存在沖突{j = (j+1)%TableSize; //用解決沖突的方法繼續查找(開放定址法)if(j == i)return -TableSize; //遍歷整個散列表,沒有空位}return j; //返回標記為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不存在,且散列表未滿(且沒有deleted標記){ht[-i].data = x; //元素賦值ht[-i].info = Active; //占用了,標記一下currentSize++;return 1;}else if(i != -TableSize && deletedSize) //元素x不存在,且散列表未滿(且有deleted標記){int j = find_de(x);if(j >= 0){if(ht[j].info == Deleted)deletedSize--;ht[j].data = x; //元素賦值ht[j].info = Active; //占用了,標記一下(刪除標記改成占用標記 )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; //找到了要刪除的,標記刪除currentSize--;deletedSize++;return 1;}else return 0; }hashtable1_test.cpp 測試程序
/*** @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; }測試結果:(data,標記位)標記 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 //鏈表節點 {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; //散列表鏈表數組int bucket; //散列表桶個數 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; //留余數法}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; //返回找到元素的前一個節點,或者沒有找到,返回最后一個元素}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_HlinkedHash_test.cpp 測試程序
/*** @description: 拉鏈法散列表 測試* @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; }測試結果:
總結
以上是生活随笔為你收集整理的数据结构--散列表 Hash Table的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怎样从php转向java_Github标
- 下一篇: 朴素贝叶斯算法--过滤垃圾短信