1.什么是哈希?
在学哈希之前,我们对于数据的查找通常是建立于顺序表、树形结构的基础上进行的。但是随着数据量越来越庞大,数据的随机性和容量越发严峻。
理想的搜索方法: 可以不经过任何比较,一次直接从表中得到要搜索的元素。
如果构造一种存储结构,通过某种函数 ( hashFunc ) 使元素的存储位置与它的关键码之间能够建立一一映射的关系,那么在查找时通过该函数可以很快找到该元素。
因此就在此基础上发展出了一种平均时间复杂度几乎为 O(1) 的数据查找方式,哈希,也称为散列。
2.哈希的常见实现方法
2.1 直接定址法
对于一段相对集中的数据段,就可以使用直接定址法。这里最大的数是 30,最小的数是 15,创建一个大小为 15 的数组,将所有值映射到数组上。
优点: 简单、均匀 缺点: 需要事先知道关键字的分布情况 使用场景: 适合查找比较小且连续的情况,数据太分散就不适合了,开的数组会太大,造成空间浪费
2.2 除留余数法
除留余数法是一种通过固定的哈希函数计算方式将数据放入哈希表的常用方法。设散列表中允许的地址数为 m,取一个不大于 m,但最接近或者等于 m 的质数 p 作为除数,按照哈希函数:Hash(key) = key % p (p <= m),将关键码转换成哈希地址。
3.哈希冲突
简单来说,通过除留余数法,将每个进来的值除以哈希表的大小得到的余数,必定是在所开哈希表的容器大小范围内的。但是有可能不同的 key 会除出相同的余数,造成同一位置的冲突,该种现象称为 哈希冲突 或 哈希碰撞。
4.哈希冲突的解决
4.1 闭散列
也叫 开放定址法,当发生哈希冲突时,如果哈希表未被装满,说明在哈希表中必然还有空位置,那么可以把 key 存放到冲突位置中的'下一个'空位置中去。那如何寻找下一个空位置呢?
4.1.1 线性探测
下面将通过对借助哈希表的实现解析线性探测相关的知识:
4.1.1.1 哈希表的基本数据结构
enum STATE { EXIST, EMPTY, DELETE };
template<class K, class V>
struct HashData {
pair<K, V> _kv;
STATE _state = EMPTY;
};
template<class K, class V, class HashFunc = DefaultHashFunc<K>>
class HashTable {
public:
() { _table.(); }
:
vector<HashData<K, V>> _table;
_n = ;
};


