上篇文章已经写过构造哈希表时用开放定址法解决哈希冲突,这次我就来写写这个开链法解决哈希冲突的问题!
一、结点定义
我们已经知道开链法大概是一种什么结构了,(如果不知道,这里有讲哦点我点我)显而易见,实现哈希桶的话我们就必须多一个指针next,至少这样才看起来有个链表的样子嘛!!
- //开链法(哈希桶)
- template<class K,class V>
- struct KVNode
- {
- K _key;
- V _value;
- KVNode<K,V>* _next;
- KVNode(const K& key,const V& value)
- :_key(key)
- ,_value(value)
- ,_next(NULL)
- {}
- };
以数组int a[] = {51, 105, 52, 3, 55, 2, 106, 53, 0}为例
Insert:
老规矩,我们还是得判断这个key在表中是否存在,如果存在就插入失败;当两个key有相同的散列地址时,我们只需将前一个结点的next指针指向新结点即可!那么,我们在同一个散列地上的链表进行插入结点时,用头插好还是尾插好呢?!当然是头插好了,这样我们就不用每次遍历到链表的尾结点,这可省了不少事儿!!
以上面这个数组为例,假设51和105分别都已经插入在正确的位置(此时表长53),接下来需要插入52,我们利用头插进行插入
如果表中的某个位置此时为NULL,当要进行插入时,做法与上述一样。
- bool Insert(const K& key,const V& value)
- {
- if (Find(key)) //已经存在这个数
- return false;
- _CheckSize();
- size_t index = _HashFunc(key,_table.size());
- Node* tmp = new Node(key,value);
- tmp->_next = _table[index];
- _table[index] = tmp;
- _size++;
- return true;
- }
Find:
首先要找到key的散列地址,再在这个地址上挂着的链表开始遍历查找,直到找到相同的key为止。
- Node* Find(const K& key)
- {
- if (_size == 0)
- return NULL;
- size_t index = _HashFunc(key,_table.size());
- Node* cur = _table[index];
- while (cur)
- {
- if (cur->_key == key)
- return cur;
- cur = cur->_next;
- }
- //没有找到
- return false;
- }
Delete:
删除一个数据时就是要删除这个结点,删除结点的方式与删除链表一个结点的方式是一样的,只要改变前一个结点的next指针。不过在这之前我们需要通过散列地址找到这个结点。假如要删除53表示的这个结点
- bool Remove(const K& key)
- {
- if(_size == 0)
- return false;
- size_t index = _HashFunc(key,_table.size());
- Node* cur = _table[index];
- Node* prev = NULL;
- while (cur)
- {
- while(cur->_key == key)
- {
- //删除的是头(第一个)结点
- if (prev == NULL)
- {
- _table[index] = cur->_next;
- }
- //删除非头结点(中间或后边)
- else
- {
- prev->_next = cur->_next;
- }
- delete cur;
- _size--;
- return true;
- }
- prev = cur;
- cur = cur->_next;
- }
- return false;
- }
具体代码:
- //开链法(哈希桶)
- template<class K,class V>
- struct KVNode
- {
- K _key;
- V _value;
- KVNode<K,V>* _next;
- KVNode(const K& key,const V& value)
- :_key(key)
- ,_value(value)
- ,_next(NULL)
- {}
- };
- template<class K,class V>
- class HashTable
- {
- typedef KVNode<K,V> Node;
- public:
- HashTable()
- :_size(0)
- {
- _table.resize(3);
- }
- ~HashTable()
- {
- for (size_t i=0; i<_table.size(); ++i)
- {
- Node* cur = _table[i];
- while (cur)
- {
- Node* tmp = cur->_next;
- delete cur;
- cur = tmp;
- }
- _size = 0;
- _table.clear();
- }
- }
- Node* Find(const K& key);
- bool Remove(const K& key);
- bool Insert(const K& key,const V& value);
- void Display()
- {
- for (size_t i=0; i<_table.size(); ++i)
- {
- printf("Table[%d]->",i);
- Node* cur = _table[i];
- while (cur)
- {
- Node* next = cur->_next;
- cout<<cur->_key<<" ";
- cur = next;
- }
- cout<<NULL;
- cout<<endl;
- }
- }
- protected:
- void _CheckSize()
- {
- if (_table.size() == 0 || _size == _table.size())
- {
- vector<Node*> tmpTable;
- tmpTable.resize(_GetPrimer(_table.size()));
- //将原表_table中的结点直接放入新表中
- for (size_t i=0; i<_table.size(); ++i)
- {
- Node* cur = _table[i];
- while (cur)
- {
- Node* next = cur->_next;
- size_t index = _HashFunc(cur->_key,tmpTable.size());
- cur->_next = tmpTable[index];
- tmpTable[index] = cur;
- cur = next;
- }
- }
- _table.swap(tmpTable);
- }
- }
- size_t _GetPrimer(size_t size)
- {
- 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 (size_t i=0; i<_PrimeSize; ++i)
- {
- if (_PrimeList[i] > size)
- {
- return _PrimeList[i];
- }
- }
- }
- size_t _HashFunc(const K& key,size_t size)
- {
- return key%size;
- }
- protected:
- vector<Node*> _table;
- size_t _size; //已有的数据个数
- };