您好,登錄后才能下訂單哦!
上篇博客我寫的是用線性探測來解決哈希表。http://10739316.blog.51cto.com/10729316/1771958
下面我在介紹另一種解決哈希表的方法,開鏈法,也叫哈希桶。下面我介紹一下這種方法的思路。
基本思路:
1.先給一個數組,這個數組中存的是指針數組,每個指針數組都指向一個數組。
2.用元素除以存儲指針數組的數組的大小。
3.余數與指針數組下標相同的,都鏈到數組指針指向的這一個數組。
我在進一步用圖表示一下:
代碼如下:
HashTable.h中
#pragma once #include <vector> template<class K,class V> struct HashTableNode { K _key; V _value; HashTableNode* _next; HashTableNode(const K& key, const V& value) :_key(key) , _value(value) , _next(NULL) {} }; template <class K,class V> class HashTable { typedef HashTableNode<K, V> Node; public: //拷貝構造 HashTable() :_table(NULL) , _size(0) {} //拷貝構造 HashTable(const HashTable<K,V>& ht) { _table.resize(ht._table.size()); for (int i = 0; i < ht._table.size(); i++) { Node* cur = ht._table[i]; while (cur) { Node* tmp = new Node(cur->_key, cur->_value); tmp->_next = _table[i]; _table[i] = tmp; _size++; cur = cur->_next; } } } //賦值運算符的重載 HashTable<K, V> operator=( HashTable<K, V> ht) { if (this != &ht) { swap(_table, ht._table); swap(_size, ht._size); } return *this; } //析構函數 ~HashTable() { if (_table.size()) { for (int i = 0; i < _table.size(); i++) { Node* cur = _table[i]; while (cur) { Node* del = cur; cur = cur->_next; delete del; del = NULL; } } } } bool Insert(const K& key, const V& value) { //是否需要擴容 if (_size == _table.size()) { _ExpandCapatity(); } size_t index = _HashFunc(key); Node* cur = _table[index]; //防冗余 while (cur) { if (cur->_key == key) { return false; } cur = cur->_next; } //插入節點 Node* tmp = new Node(key, value); tmp->_next = _table[index]; _table[index] = tmp; _size++; return true; } Node* Find(const K& key) { size_t index = _HashFunc(key); Node* cur = _table[index]; while (cur) { if (cur->_key == key) { return cur; } cur = cur->_next; } return NULL; } bool Remove(const K& key) { size_t index = _HashFunc(key); Node* cur = _table[index]; Node* prev = NULL; //找到要刪除的元素 while (cur) { if (cur->_key == key) { break; } prev = cur; cur = cur->_next; } if (cur) { //頭刪 if (cur == _table[index]) { _table[index] = cur->_next; } //刪除中間元素 else { Node* next = cur->_next; prev->_next = next; } delete cur; cur = NULL; _size--; return true; } return false; } void Print() { for (int i = 0; i < _table.size(); i++) { Node* cur = _table[i]; cout << i << ":"; while (cur) { cout << cur->_key << " "; cout << cur->_value << " "; cur = cur->_next; } if (_table[i] == NULL) { cout << "NULL"; } cout <<endl; } cout << endl; } protected: //算出應該鏈接到哈希桶的那個位置 size_t _HashFunc(const K& key) { return key%_table.size(); } //新的容量 size_t _NewSize() { // 使用素數表對齊做哈希表的容量,降低哈希沖突 const int _PrimeSize = 28; static const unsigned long _PrimeList[_PrimeSize] = { 53ul, 97ul, 193ul, 389ul, 769ul, 1543ul, 3079ul, 6151ul, 12289ul, 24593ul, 49157ul, 98317ul, 196613ul, 393241ul, 786433ul, 1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul, 50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul, 1610612741ul, 3221225473ul, 4294967291ul }; for (int i = 0; i < _PrimeSize; i++) { if (_PrimeList[i]>_table.size()) { return _PrimeList[i];//按照素數表來設置容量大小 } } //當需要的容量超過素數表的最大容量,我們就按照最大的來擴容 return _PrimeList[_PrimeSize - 1]; } //哈希桶擴張容量 void _ExpandCapatity() { //開辟一個新的更大容量哈希桶 size_t newsize = _NewSize(); vector<Node*> newtable; newtable.resize(newsize); //把原來哈希桶中的元素再下來,插入到新的哈希桶 for (int i = 0; i < _table.size(); i++) { Node* cur = _table[i]; while (cur) { Node* tmp = cur; int index = _HashFunc(tmp->_key); //頭插法 tmp->_next = newtable[index]; newtable[index] = tmp; cur = cur->_next; } _table[i] = NULL; } _table.swap(newtable); } protected: vector<Node*> _table; size_t _size;//數據的多少 };
為了減少哈希沖突,我擴張容量是用到了素數表。你們如果想問我為什么用素數表能減少哈希沖突,其實我也不知道,我只是知道別人這樣說,我拿來用而已。
//新的容量 size_t _NewSize() { // 使用素數表對齊做哈希表的容量,降低哈希沖突 const int _PrimeSize = 28; static const unsigned long _PrimeList[_PrimeSize] = { 53ul, 97ul, 193ul, 389ul, 769ul, 1543ul, 3079ul, 6151ul, 12289ul, 24593ul, 49157ul, 98317ul, 196613ul, 393241ul, 786433ul, 1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul, 50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul, 1610612741ul, 3221225473ul, 4294967291ul }; for (int i = 0; i < _PrimeSize; i++) { if (_PrimeList[i]>_table.size()) { return _PrimeList[i];//按照素數表來設置容量大小 } } //當需要的容量超過素數表的最大容量,我們就按照最大的來擴容 return _PrimeList[_PrimeSize - 1]; } //哈希桶擴張容量 void _ExpandCapatity() { //開辟一個新的更大容量哈希桶 size_t newsize = _NewSize(); vector<Node*> newtable; newtable.resize(newsize); //把原來哈希桶中的元素再下來,插入到新的哈希桶 for (int i = 0; i < _table.size(); i++) { Node* cur = _table[i]; while (cur) { Node* tmp = cur; int index = _HashFunc(tmp->_key); //頭插法 tmp->_next = newtable[index]; newtable[index] = tmp; cur = cur->_next; } _table[i] = NULL; } _table.swap(newtable); }
希望自己的理解能幫到大家,如果有什么錯誤,希望大家及時提出,謝謝!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。