哈希表,又称为散列表,它是根据关键码(key)直接访问在内存中的存储的一种数据结构。它通过把关键码根据某一函数进行转换后映射到表中的,这个函数称为散列函数,存放记录的数组称为散列表。
一、哈希表的构造
如何构造一个散列表?!请看这篇博客^-^:散列表的构造和哈西冲突
值得一提的是,构造这个表时,我们需要考虑这个位置的状态,是EMPTY,EXIST 还是DELETE?!当表中还没有元素时,我们给的默认状态是EMPTY。
二、哈希表实现Insert、Remove、Find(这篇文章我是用开放定址法处理哈希冲突)
Insert:
每插入一个数,就将该位置的状态改为EXIST,当插入的下一个数如果也映射在该位置,看到这个标志"EXIST"就知道这个位置已经被占用,就继续去探测下一个状态为"EMPTY"或"DELETE"的位置;如果插入的过程中发现已经有相同的key值,那么就直接返回
-
- bool Insert(const K& key,const V& value)
- {
-
- _CheckSize();
-
-
- size_t index = _HashFunc(key);
- while (_table[index]._status == EXIST)
- {
-
- if (_table[index]._key == key)
- {
- return false;
- }
-
- if (_table[index]._status == EMPTY || _table[index]._status == DELETE)
- {
- break;
- }
- ++index;
-
-
- if (index == _table.size())
- {
- index = 0;
- }
- }
-
-
- _table[index]._key = key;
- _table[index]._value = value;
- _table[index]._status = EXIST;
- _size++;
- return true;
- }
Find:
查找数据时,也是根据关键码key来寻找的,只要这个位置的状态不为"EMPTY"时,就可以一直寻找,当某一位置的key符合条件时就返回该位置的位置;还有一种情况是找到表尾时没有找到,那么就应该先回表头继续寻找。
- Node* Find(const K& key)
- {
-
- if (_table.size() == 0)
- {
- return false;
- }
- size_t index = _HashFunc(key);
- while (_table[index]._status != EMPTY)
- {
- if (_table[index]._key == key)
- {
- return &_table[index];
- }
- ++index;
-
- if (index == _table.size())
- {
- index = 0;
- }
- }
- }
Delete:
这里删除数据时我们采用的是“懒删除法”,即直接修改该位置的状态为"DELETE"。由于在插入数据时只关心的是该位置的状态是否为"EXIST",所以其他状态并不会对插入有影响,就算下一次插入数据的位置状态是"DELETE",直接覆盖掉就好了!!
- bool Remove(const K& key)
- {
- for (size_t index=0; index<_table.size(); ++index)
- {
- if (_table[index]._key == key)
- {
- _table[index]._status = DELETE;
- return true;
- }
- }
- return false;
- }
具体代码实现:
- enum STATUS
- {
- EMPTY,
- EXIST,
- DELETE,
- };
-
- template<class K,class V>
- struct KVNode
- {
- K _key;
- V _value;
- STATUS _status;
-
- KVNode(const K& key,const V& value)
- :_key(key)
- ,_value(value)
- ,_status(EMPTY)
- {}
- };
-
- template<class K,class V>
- class HashTable
- {
- typedef KVNode<K,V> Node;
- public:
- HashTable()
- :_size(0)
- {
- _table.resize(_GetPrimer(0));
- }
- ~HashTable()
- {
- for (size_t i=0; i<_table.size(); ++i)
- {<span style="white-space:pre"> </span>
- _table[i]._key = 0;
- _table[i]._value = 0;
- _table[i]._status = EMPTY;
- }
- }
-
- 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)
- {
- if (_table[i]._status == EXIST)
- {
- cout<<"key->"<<_table[i]._key<<" "<<"value->"<<_table[i]._value<<endl;
- }
- }
- }
- protected:
- void _CheckSize()
- {
-
-
-
- if (_table.size() == 0 || _size*10/_table.size() >= 8)
- {
- size_t newSize = _GetPrimer(_table.size());
- HashTable<K,V> newHashTable;
- newHashTable._table.resize(newSize);
-
- for (size_t i=0; i<_table.size(); ++i)
- {
- if (_table[i]._status == EXIST)
- {
- newHashTable.Insert(_table[i]._key,i);
- }
- }
- swap(this->_table,newHashTable._table);
- swap(_size,newHashTable._size);
- }
- }
-
- 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)
- {
- return key%_table.size();
- }
- protected:
- vector<Node> _table;
- size_t _size;
- };
ps:下篇文章会实现开链法解决哈希冲突!