定义
- 闭散列法,又称开放定址法,当发生哈希冲突时,如果哈希表未被装满,说明在哈希表中必然还有空位置,那么可以把key存放到冲突位置中的“下一个”空位置中去。
如何寻找下一个空位置
- 线性探测法:从发生冲突的位置开始,依次向后探测,直到寻找到下一个空位置为止;
缺点:一旦发生哈希冲突,所有的冲突连在一起,容易产生数据“堆积”,导致搜索效率降低; - 二次探测法:按2次方去找“下一个”空位置。
基于闭散列法实现哈希
1)实现基本框架
hashDate
enum Status{
EMPTY,
EXITS,
DELETE
};
template <class K, class V>
struct HashData{
pair<K, V> _kv;
Status _status = EMPTY;
};
hashTable
- 对于自定义类型,其构造、拷贝构造、赋值重载、析构等默认成员函数,编译器会自动生成
- 哈希表里的数据类型为hashData
template <class K, class V, class HashFunc>
class HashTable{
private:
vector<HashData<K, V>> _table;
size_t _n;
};
hashFunc
- hashFunc仿函数:实现key值转化为int型,保证在哈希函数运算时能进行取模运算
struct intHashFunc{
int operator()(int i){
return i;
}
};
struct stringHashFunc{
int operator()(string s){
int count = 0;
for (auto &e : s){
count += e;
}
return count;
}
};
2)实现基本操作
insert插入操作
- 判断是否需要插入-----是否需要增容(负载因子>0.5)-----线性探测法找待插入位置-----插入元素
bool insert(const pair<K, V>& kv){
if (_table.size() == 0){
_table.resize(8);
}
HashFunc hf;
HashData<K, V>* ret = find(kv.first);
if (ret != nullptr){
return true;
}
if ((double)_n / (double)_table.size() > 0.5){
HashTable<K, V, HashFunc> newhash;
newhash._table.resize(_table.size() * 2);
for (auto& e : _table){
if (e._status == EXITS)
newhash.insert(e._kv);
}
_table.swap(newhash._table);
}
size_t start = hf(kv.first) % _table.size();
size_t index = start;
size_t i = 1;
while (_table[index]._status == EXITS){
index = start + i;
index %= _table.size();
++i;
}
_table[index]._kv = kv;
_table[index]._status = EXITS;
_n++;
return true;
}
find查找操作
HashData<K, V>* find(const K& key){
HashFunc hf;
size_t start = hf(key) % _table.size();
size_t index = start;
size_t i = 1;
while (_table[index]._status != EMPTY){
if (_table[index]._status == EXITS && _table[index]._kv.first == key){
return &_table[index];
}
index = start + i;
index %= _table.size();
++i;
}
return nullptr;
}
erase删除操作
- 查找待删除元素的位置-----该元素的状态置为DELETE即可
bool erase(const K& key){
HashData<K, V>* ret = find(key);
if (ret){
ret->_status = DELETE;
return true;
}
else
return false;
}