哈希表基础
理解哈希表,首先要区分'哈希'与'哈希表'。哈希是一种映射算法思想,而哈希表则是基于这种思想构建的数据结构。
所有哈希表的算法流程基本一致:获取一个 key,通过哈希函数计算 hash(key),得到存储位置存放 Value;或者从该位置取出查找的 Value。
理解哈希表
深入理解哈希表通常分为三层:
- 哈希值:这是最基础的整数映射。
- 哈希函数:将哈希值映射到具体空间位置。
- 哈希冲突:解决不同键映射到同一位置的问题。
STL 中的哈希表底层逻辑也是先获取哈希值(整形),再通过哈希函数处理。无论 Key 是 string 还是 vector,最终都需要转换为哈希值才能存入。
因此理解链条应为:哈希值 → 哈希函数 → 哈希冲突。
最基本的哈希表逻辑上可视为数组。数组有大小限制,当数据过多时必然发生哈希冲突。哈希是功能,冲突是可能结果,两者存在因果关系。
哈希值(整形)
为什么需要哈希值?因为大多数哈希函数(如除留余数法、平方取中法等)都是对整形进行运算。在 STL 中,若要对自定义类型进行哈希,必须提供该类型向哈希值的转换方法,即'转换策略'。
有了转换策略,自定义类型即可转为哈希值,再交给底层哈希函数处理。转化哈希值通常定义为仿函数,作为 unordered_map 的第三个模板参数传入。
设计转换策略时需注意速度快、离散度高。常见策略包括:
- BKDR 哈希:适用于字符串。
- 异或组合:适用于简单容器。
- hash_combine:适用于复杂结构体。
BKDR 哈希
优点是实现简单、计算快、离散度高。选取种子 seed,遍历字符串每个字符进行处理。
size_t BKDRHash(const string &str) {
size_t seed = 131; // 常用种子:31, 131, 1313...
size_t hash = 1;
for (auto e : str) {
hash *= seed;
hash += e;
}
return hash & 0x7FFFFFFF; // 确保返回正数
}
异或组合
实现简单,但冲突率相对较高。
struct PointHash {
size_t operator()(const vector<int> &vec) {
hash = ;
( e : vec) {
hash ^= (e << );
}
hash;
}
};


