散列表的基本概念与散列函数
散列表是本章唯一一种「不靠比较来定位」的查找结构。
前面所有方法——顺序、折半、二叉排序树、B 树——教材的原话是:记录在表中的位置与记录的关键字之间不存在映射关系,因此在这些表中的查找效率取决于比较的次数。 散列表反过来:建立了关键字和存储地址之间的一种直接映射关系,理想情况下查找的时间复杂度是
代价是「映射」不可能一一对应,于是有了冲突。这一章 7.5 的四个小节其实就是四个问题:怎么映射(7.5.2)、撞了怎么办(7.5.3)、撞完之后到底多快(7.5.4)。
机制
三个定义
| 术语 | 定义 |
|---|---|
| 散列函数(哈希函数) | 一个把查找表中的关键字映射成该关键字对应的地址的函数,记为 |
| 冲突 / 同义词 | 散列函数可能会把两个或两个以上的不同关键字映射到同一地址,称这种情况为冲突,这些发生冲突的不同关键字称为同义词 |
| 散列表(哈希表) | 根据关键字而直接进行访问的数据结构。散列表建立了关键字和存储地址之间的一种直接映射关系 |
教材对冲突的态度写得很清楚,两句话是一对:
一方面,设计得好的散列函数应尽量减少这样的冲突;另一方面,因为这样的冲突总是不可避免的,所以还要设计好处理冲突的方法。
边界辨析:
「同义词」指的是关键字,不是地址。 两个关键字算不算同义词,只看
是否相等, 与用什么方法处理冲突、最终存到哪个位置无关。 用 线性探测 把同义词挪到别处之后,它们仍然是同义词; 而两个非同义词被挤到相邻位置引起的堆积,不叫同义词冲突——2014 年就考过这个区分。
构造散列函数的三条要求
- 散列函数的定义域必须包含全部关键字,而值域的范围则依赖于散列表的大小。
- 散列函数计算出的地址应尽可能均匀地分布在整个地址空间,尽可能地减少冲突。
- 散列函数应尽量简单,能在较短的时间内计算出任意一个关键字对应的散列地址。
第 1 条的后半句是 7.5.4 算
四种散列函数
1. 直接定址法
直接取关键字的某个线性函数值为散列地址:
式中
2. 除留余数法
这是一种最简单、最常用的方法。假定散列表表长为
除留余数法的关键是选好
3. 数字分析法
设关键字是
4. 平方取中法
取关键字的平方值的中间几位作为散列地址。这种方法得到的散列地址与关键字的每位都有关系,因此使得散列地址分布比较均匀,适用于关键字的每位取值都不够均匀或均小于散列地址所需的位数。
在不同的情况下,不同的散列函数具有不同的性能,因此不能笼统地说哪种散列函数最好。在实际选择中,采用何种构造散列函数的方法取决于关键字集合的情况。
边界辨析:
和 是两个数,不要混。 是散列表的表长(数组开多大), 是除留余数法里的模数(不大于 的最接近的质数)。 教材 7.5.4 的例子里 而 ——散列函数用 , 而 开放定址 探测下一个地址时用的是 。 两个模数在同一道题里同时出现,是散列表计算题最集中的失分点。
手算模板
给定关键字序列建散列表:
- 抄下
(表长)和散列函数(多半是 )。先把 和 分别圈出来。 - 按给定的插入顺序逐个算
。 - 位置空 → 放进去,比较次数记 1。
- 位置非空 → 按 7.5.3 的方法探测,每探测一次比较次数 +1。
- 边放边在旁边记下每个关键字的比较次数——这张表直接就是
的分子。
边界
| 说法 | 判断 | 说明 |
|---|---|---|
| 「散列查找不需要任何关键字的比较」 | ❌ | 定位到地址后仍要比较该位置的关键字与 key 是否相等 |
| 「散列表的查找一定是 | ⚠️ | 理想情况下是;有冲突时取决于装填因子和处理冲突的方法 |
| 「同义词是指存储位置相同的关键字」 | ❌ | 是散列函数值相同的关键字,与最终存放位置无关 |
| 「装填因子 | ❌ | 冲突取决于散列函数把哪些 key 映到同一地址,与表满不满无关 |
| 「直接定址法会产生冲突」 | ❌ | 不会产生冲突,但可能浪费空间 |
| 「除留余数法的 | ❌ | 取不大于 |
| 「 | ❌ | |
| 「数字分析法适用于任何关键字集合」 | ❌ | 适用于已知的关键字集合;换了关键字要重构 |
| 「平方取中法只与关键字的中间几位有关」 | ❌ | 平方之后的中间几位与关键字的每一位都有关系 |
| 「散列函数越复杂越好」 | ❌ | 第 3 条要求是尽量简单 |
口径差异:
算法竞赛里写哈希是为了抗卡:随机化模数、双哈希、
unordered_map换gp_hash_table, 关心的是最坏情况会不会被构造数据打爆。 408 完全不考这些,考的是「给定和冲突处理方法,把表填出来、把两个 算出来」。 另外,「哈希」这个音译词在 408 里一律写成「散列」, 「散列表」「散列函数」「散列地址」是标准术语,答题时按教材用词更稳。
对照速查
| 散列函数 | 公式 | 特点 | 适用 |
|---|---|---|---|
| 直接定址法 | 绝不冲突,可能浪费空间 | 关键字分布基本连续 | |
| 除留余数法 | 最简单最常用,关键在选 | 通用; | |
| 数字分析法 | 取分布均匀的若干位 | 依赖关键字集合 | 关键字集合已知且各位分布不均 |
| 平方取中法 | 取 | 与每一位都有关 | 各位取值都不够均匀 |
| 符号 | 含义 |
|---|---|
| 散列表表长 | |
| 除留余数法的模数, | |
| 表中记录数 | |
| 装填因子(见 7.5.4) |
考点
- 散列表 / 散列函数 / 冲突 / 同义词四个定义的准确措辞。
- 同义词看的是
相等,不是存储位置相等。 - 构造散列函数的三条要求,尤其「值域依赖表大小」。
- 四种散列函数的适用场合,直接定址法不产生冲突。
- 除留余数法的
是不大于 的最接近质数。 与 的区分——散列用 ,探测用 。
链接
- 🏠 返回总览:数据结构第 7 章:查找总览
- ⬅️ 上一节:7.4.2 B+树的基本概念
- ➡️ 下一节:7.5.3 处理冲突的方法
- 🔗 性能与装填因子:7.5.4 散列查找及性能分析
- 🔗 静态与动态都适用:7.1 查找的基本概念
- 📖 名词库:第 7 章名词库