【数据结构】哈希表:构造与冲突处理

考点频率 :★★★★★(数据结构必考,选择题常考ASL计算,下午题偶尔结合查找考查)

难度 :⭐⭐⭐⭐(冲突处理和ASL计算需要重点理解)

建议:重点掌握哈希函数的构造(除留余数法)、冲突解决(开放地址法/链地址法),以及平均查找长度(ASL)的计算

1️⃣ 为什么需要哈希表?

前面我们学了顺序查找(O(n)O(n)O(n))和折半查找(O(log⁡n)O(\log n)O(logn))。它们都有一个共同点:查找过程依赖于"比较"------需要不断地将目标值与表中的元素进行比较。

有没有一种方法,不需要比较,直接通过一次计算就能找到目标元素?

这就是哈希表(Hash Table) 的核心思想:

哈希表通过一个"哈希函数",将关键字(Key)直接映射到表中的某个位置,从而实现 O(1)O(1)O(1) 级别的查找速度。
打个比方:你去图书馆还书,如果图书管理员按书名首字母把书分到不同的架子上(哈希函数),你只要知道书名首字母,就能直接走到对应的架子前(定位),而不需要在一排排书架中一本一本找(比较)。如果书放满了,管理员会把同字母的书放在同一层的不同位置(冲突处理)。

哈希表的关键问题

  1. 哈希函数怎么设计? ------ 让关键字分布均匀
  2. 冲突怎么处理? ------ 当两个不同的关键字映射到同一个位置时

2️⃣ 哈希函数的构造方法

软考中主要考查以下五种方法,其中 "除留余数法" 是考查频率最高的:

方法 公式 适用场景 软考考频
直接定址法 H(key)=a×key+bH(key) = a \times key + bH(key)=a×key+b 关键字分布连续且已知 ★☆☆☆☆
数字分析法 取关键字中分布均匀的若干位作为地址 关键字位数较多,且知道分布规律 ★★☆☆☆
平方取中法 取关键字平方后的中间几位作为地址 关键字不规律,位数较少 ★☆☆☆☆
折叠法 将关键字分割成几部分,叠加后取低几位 关键字位数较多 ★☆☆☆☆
除留余数法 H(key)=key  mod  pH(key) = key \ \bmod \ pH(key)=key mod p(ppp 为不大于表长的最大质数) 最常用,软考重点 ★★★★★

除留余数法的关键 :ppp 的选择直接影响冲突率。通常取 不大于哈希表长度 mmm 的最大质数。因为质数能减少取模运算后的规律性,使关键字分布更均匀,从而降低冲突概率。

示例 :哈希表长度 m=16m = 16m=16,不大于16的最大质数是13,则取 p=13p = 13p=13,哈希函数为 H(key)=key mod 13H(key) = key \bmod 13H(key)=keymod13。

3️⃣ 冲突处理的两种核心方法(必考)

3.1 开放地址法(Open Addressing)

核心思想 :当发生冲突时,按照某种规则在哈希表中寻找下一个空闲位置

通用公式:Hi(key)=(H(key)+di) mod mH_i(key) = (H(key) + d_i) \bmod mHi(key)=(H(key)+di)modm,其中 did_idi 为增量序列。

根据增量序列的不同,分为三种方式:

方式 增量序列 did_idi 特点 缺点
线性探测法 di=1,2,3,...d_i = 1, 2, 3, \dotsdi=1,2,3,... 逐个向后查找空位 容易产生"堆积"------连续冲突导致查找链变长
二次探测法 di=12,−12,22,−22,...d_i = 1^2, -1^2, 2^2, -2^2, \dotsdi=12,−12,22,−22,... 跳跃式查找,减少堆积 可能无法探测所有位置
伪随机探测法 did_idi 为伪随机数序列 分布更均匀 实现复杂

示例(线性探测) :H(key)=key mod 7H(key) = key \bmod 7H(key)=keymod7,依次插入 50,85,9250, 85, 9250,85,92

  • 50:50 mod 7=150 \bmod 7 = 150mod7=1,位置1空 → 放入位置1
  • 85:85 mod 7=185 \bmod 7 = 185mod7=1,位置1已被50占据 → 线性探测 di=1d_i=1di=1:(1+1) mod 7=2(1+1) \bmod 7 = 2(1+1)mod7=2,位置2空 → 放入位置2
  • 92:92 mod 7=192 \bmod 7 = 192mod7=1,位置1、2都被占据 → 探测位置3 → 放入位置3

记忆点 :线性探测就像停车找车位------你停在目标车位发现有人,就往后开一个车位看看,再不行就再往后开一个。

3.2 链地址法(拉链法)

核心思想 :将所有映射到同一个哈希地址的关键字存储在同一个链表中。

复制代码
哈希表:
位置0: 50 → 85 → 92
位置1: 21
位置2: NULL
...

优点

  • 不会产生堆积,查找效率更稳定
  • 删除操作简单(直接从链表中删除)
  • 表的利用率高(不需要预留空间解决冲突)

缺点

  • 需要额外的指针存储空间
  • 链表过长时,查找效率退化为 O(n)O(n)O(n)

链地址法 vs 开放地址法:链地址法用链表解决冲突,更常用;开放地址法在哈希表填得较满时查找效率会急剧下降。

4️⃣ 装填因子 α\alphaα(理解概念)

装填因子(Load Factor) :α=nm\alpha = \frac{n}{m}α=mn,其中 nnn 为已填入的元素个数,mmm 为哈希表长度。

  • α\alphaα 越大,冲突概率越高,查找效率越低
  • α\alphaα 越小,空间浪费越多
  • 一般控制 α\alphaα 在 0.6∼0.80.6 \sim 0.80.6∼0.8 之间

在开放地址法中,平均查找长度与 α\alphaα 直接相关------α\alphaα 越大,查找链越长。

5️⃣ 平均查找长度(ASL)计算(软考核心考点)

软考几乎每年都会考一道计算哈希表在查找成功和查找失败时的平均查找长度的题目。

5.1 查找成功时的 ASL(ASL成功ASL_{成功}ASL成功)

ASL成功=所有关键字的查找次数之和关键字总数ASL_{成功} = \frac{\text{所有关键字的查找次数之和}}{\text{关键字总数}}ASL成功=关键字总数所有关键字的查找次数之和

查找次数 :从哈希地址开始,沿探测序列找到该关键字所经历的比较次数(包括和关键字本身的比较)。

5.2 查找失败时的 ASL(ASL失败ASL_{失败}ASL失败)

ASL失败=所有可能地址的查找失败次数之和哈希表地址总数ASL_{失败} = \frac{\text{所有可能地址的查找失败次数之和}}{\text{哈希表地址总数}}ASL失败=哈希表地址总数所有可能地址的查找失败次数之和

查找失败次数 :从该地址开始沿探测序列查找,直到遇到空位置 为止所经历的比较次数

示例 :哈希函数 H(key)=key mod 7H(key) = key \bmod 7H(key)=keymod7,表长7,关键字序列 {50, 85, 92},用线性探测法:

  • 50在位置1,查找成功比较1次
  • 85在位置2(冲突1次),查找成功比较2次
  • 92在位置3(冲突2次),查找成功比较3次
  • ASL成功=(1+2+3)/3=2ASL_{成功} = (1+2+3)/3 = 2ASL成功=(1+2+3)/3=2
  • 查找失败:地址0查找失败需比较1次(空),地址1需比较4次(1→2→3→4空),地址2需比较3次,地址3需比较2次,地址4需比较1次,地址5需比较1次,地址6需比较1次,ASL失败=(1+4+3+2+1+1+1)/7=13/7≈1.86ASL_{失败} = (1+4+3+2+1+1+1)/7 = 13/7 \approx 1.86ASL失败=(1+4+3+2+1+1+1)/7=13/7≈1.86

6️⃣ 经典例题

例题1 :哈希表长度为11,哈希函数为 H(key)=key mod 7H(key) = key \bmod 7H(key)=keymod7,用线性探测法处理冲突。依次插入关键字 {22, 34, 55, 68, 41, 89},求 ASL成功ASL_{成功}ASL成功。

解析

  • 22:22%7=1 → 位置1(比较1次)
  • 34:34%7=6 → 位置6(比较1次)
  • 55:55%7=6 → 位置6冲突→7(比较2次)
  • 68:68%7=5 → 位置5(比较1次)
  • 41:41%7=6 → 位置6冲突→7冲突→8(比较3次)
  • 89:89%7=5 → 位置5冲突→6冲突→7冲突→8冲突→9(比较4次)
    ASL成功=(1+1+2+1+3+4)/6=12/6=2ASL_{成功} = (1+1+2+1+3+4)/6 = 12/6 = 2ASL成功=(1+1+2+1+3+4)/6=12/6=2

答案 :ASL成功=2ASL_{成功} = 2ASL成功=2


例题2:以下关于哈希表的叙述中,正确的是( )。

A. 哈希表的查找效率一定高于折半查找

B. 链地址法处理冲突时,删除操作比开放地址法更复杂

C. 装填因子 α\alphaα 越大,查找效率越高

D. 线性探测法容易产生"堆积"现象

解析 :A错误------哈希表在最坏情况下查找效率可能很低;B错误------链地址法删除比开放地址法更简单(直接从链表删除,开放地址法删除需特殊标记);C错误------α\alphaα 越大冲突越多,效率越低;D正确。选 D

7️⃣ 记忆口诀

哈希函数除留余,质数取模分布均。

线性探测遇空停,堆积现象易形成。

链地址法链表存,删除方便效率稳。

ASL成功看总次数,失败看空位探针。

8️⃣ 小测验(评论区对答案)

哈希表长度为10,哈希函数 H(key)=key mod 7H(key) = key \bmod 7H(key)=keymod7,用线性探测法处理冲突。依次插入 {15, 22, 29, 36, 43},ASL成功ASL_{成功}ASL成功 为( )。

A. 1.0

B. 1.4

C. 1.8

D. 2.2

🔔 本专栏日更,点击头像 → 专栏《软考中级高频考点》订阅,第一时间接收新内容

#软考中级 #软件设计师 #哈希表 #散列表 #冲突处理 #数据结构 #软考备考

相关推荐
Wang's Blog2 小时前
PostgreSQL笔记50: 基于PGVECTOR的实时推荐与搜索系统构建
笔记·postgresql
淡海水2 小时前
03-02-线性-List-T-动态数组布局-扩容与操作成本
数据结构·windows·c#·list·编译·clr·机器码
小飞学编程...11 小时前
【哈希表】
数据结构·哈希算法·散列表
liuyicenysabel13 小时前
多服务上线日记三:
运维·服务器·笔记·学习
CHENGQUAN_kenan13 小时前
佛山亚马逊卖家出口退税合规指南|9610免税、一般贸易退税、无票采购、申报误区全覆盖
大数据·经验分享·笔记·百度
重生之后端学习14 小时前
283. 移动零[简单]✅
开发语言·数据结构·算法·leetcode·职场和发展
一只小小的芙厨14 小时前
基础数论总结
笔记·学习·算法
动词ing15 小时前
【C语言】结构体+文件基础
c语言·开发语言·数据结构
@Mike@17 小时前
09-数据库学习笔记(数据库索引与过滤器)
数据库·笔记