哈希表核心概念
哈希表(散列表)是一种'key-value'存储结构,核心是哈希函数和冲突解决策略。通过哈希函数建立 key 与存储位置的映射,实现增删查改平均 O(1) 的时间复杂度,广泛应用于 unordered_map、缓存、字典等场景。
一. 哈希表核心概念
1.1 哈希表的本质
- 哈希函数:将 key 映射到哈希表的存储位置(下标),公式为
h(key) = 存储位置; - 核心目标:让 key 均匀分布,减少冲突,保证 O(1) 平均效率。
1.2 哈希冲突
两个不同的 key 通过哈希函数计算出相同的存储位置,称为哈希冲突。冲突无法避免,只能通过优化哈希函数和冲突解决策略减少影响。
1.3 负载因子
衡量哈希表拥挤程度的指标,公式为:负载因子 (λ) = 存储的元素个数 (N) / 哈希表大小 (M)。
- λ 越大:冲突概率越高,空间利用率越高;
- λ 越小:冲突概率越低,空间利用率越低;
- 实践中:开放定址法 λ 通常控制在 0.7 以内,链地址法 λ 控制在 1 以内。
1.4 将关键字转为整数
我们将关键字映射到数组中位置,一般是整数好做映射计算。如果不是整数,我们要想办法转换成整数,这个细节我们后面代码实现中再进行细节展示。下面哈希函数部分我们讨论时,如果关键字不是整数,那么讨论的 Key 是关键字转换成的整数。
二. 哈希函数设计
好的哈希函数能让 key 均匀分布,减少冲突,常用设计方法如下:
2.1 直接定址法
直接用 key 或 key 的线性变换作为存储位置,公式:h(key) = a*key + b。
- 适用场景:key 范围集中(如 0-99、a-z);
- 优点:无冲突,效率高;
- 缺点:key 范围分散时浪费内存(如 key 为 1、10000,需开 10001 大小的数组)。
在关键字的范围比较集中时,直接定值法就是非常高效的方法。比如一组关键字都在 [0, 99] 之间,那么我们开一个 100 个数的数组,每个关键字的值直接就算存储位置的下标。再比如一组关键字值都在 [a, z] 的小写字母,那么我们开一个 26 个数的数组,每个关键字 ascii 码和 -'a' 的 ascii 码就是存储位置的下标。
实战举例:字符串中的第一个唯一字符
class Solution {
public:
int firstUniqChar(string s) {
int count[26] = {0};
for (auto ch : s) {
count[ch - ]++;
}
( i = ; i < s.(); i++) {
(count[s[i] - ] == ) {
i;
}
}
;
}
};


