数据结构基础——Hashing(散列)

Hashing(散列)速记模板


一、核心目标

Hashing = 用函数 f(x) 直接定位位置,实现平均 O(1) 查找/插入/删除。


二、四拍理解(必须背)

① 定义:symbol table = key → value

② 冲突:不同key映射到同一位置

③ 解决:链表 or open addressing

④ 验证:平均 O(1),依赖装填因子 α


三、Hash函数设计

1. 基本原则

✔ 计算快

✔ 分布均匀

✔ 减少周期性冲突


2. 常见函数

整数:h(x)=x mod TableSize(TableSize最好取素数)

字符串:h(x)=Σ(xi·32^i) mod M(用<<5代替×32)


四、冲突解决两大类


1. Separate Chaining(拉链法)

思想 同一桶挂链表

装填因子 α = N / M

性质

✔ α可以 >1

✔ 平均查找 O(1+α)

α≈1最优


2. Open Addressing(开放定址)

思想

冲突就往表内找空位 h_i(x) = (h(x)+f(i)) mod M


三种方式

线性探测:f(i)=i(易聚集)

平方探测:f(i)=i²(缓解聚集)

双散列:f(i)=i·h2(x)(最好)


关键问题

✔ 装填因子必须 <0.5(否则性能急剧下降)

✔ 删除要 lazy delete(标记删除)


五、重要现象


1. 一次聚集(primary clustering)

线性探测导致:

连续占用 → 越来越长 → 更容易冲突


2. 二次聚集(secondary clustering)

平方探测:

相同hash值 → 探测序列相同


六、平方探测核心定理


半满定理

当:

  • TableSize为素数

  • α < 0.5

则:✔ 一定可以找到空位


证明核心

平方探测前 n/2 个位置不重复 → 不会卡死


七、复杂度总结


Separate Chaining:

  • 平均 O(1+α)

Open Addressing:

  • 成功查找 O(1/(1−α))

  • 不成功查找更慢


八、真题讲解

collision定义?不同key → 同一hash值


2.【2015-2016 1-6】

insert vs find复杂度 ✔ 相同(平均)

原因:都依赖冲突链长度

错误点通常是:

❌ "α=0.5仍保证成功"

❌ "double hashing=quadratic probing"

❌ "插入复杂度固定O(1)"


6.【R2-12】

unsuccessful search probe length

线性探测下:平均失败查找 ≈ 1/(1−α)


7.【2023-2024 T/F】

表size=8仍能失败?✔ True

原因:平方探测可能无法覆盖所有位置(非素数)

9.【double hashing平均查找】

核心:比linear probing更均匀 → 更接近O(1)


10.【R2-13】

线性探测最小probe次数

所有key同hash:

→ 1+2+3+...+n = n(n+1)/2

九、考试最重要总结

⭐ 一、三句话核心

✔ Hashing = O(1)均摊

✔ 冲突 = unavoidable

✔ 解决 = chaining / probing


⭐ 二、装填因子

方法 α
chaining 可 >1
open addressing 必须 <0.5

⭐ 三、探测方式

线性 → 聚集严重

平方 → 改善但有限

双散列 → 最优


⭐ 四、必考公式

成功查找:1/(1−α)

失败查找:1/(1−α)²


⭐ 五、一句话总结

Hashing = 用函数直接定位 + 冲突用结构或探测解决,使平均复杂度保持 O(1)。

再散列(Rehashing)+ Robin Hood Hashing 速记

当开放定址哈希表过满或性能下降时:

重新建一个更大的表(通常约2倍+取素数),把所有合法元素重新插入。

二、复杂度

单次:O(N);均摊后 O(1)


三、触发条件(超级重点)

✔ 插入失败

✔ 装填因子 α ≥ 0.5(开放定址)

✔ 性能明显下降


四、关键规则

✔ 新表必须取素数

✔ 删除元素不搬(lazy delete只跳过)

✔ 所有元素重新hash(不是搬位置)


五、为什么要再散列?

因为开放定址:

  • α越大 → probe越长

  • 最坏 → 插入失败


六、Rehashing本质总结

通过扩大表长,降低装填因子 α,使探测序列恢复O(1)平均性能


七、真题讲解(Rehashing)


1.【2020-2021 R2-16】

何时必须rehash?

✔ insertion fails → 必须

❌ half full → 不一定必须

clustering 聚类 → 不能直接触发

❌ hash不均匀 → 不属于必要条件

✔ 必须:

  • 表过满

  • 插入失败

❌ 不必须:

  • 冲突模式变化

  • clustering出现

八、Robin Hood Hashing(重点选讲)


核心思想

线性探测改进:

"走得远的人优先"


定义探测距离

d(x) = 实际位置 − hash位置


核心规则

当新元素进入:

✔ 如果新元素探测距离 > 当前元素

→ 交换(劫富济贫)


一句话解释

把"走得太远的人"拉回去,让"更惨的继续往前"


九、Robin Hood特点


✔ 优点

  • 降低方差

  • 查找更稳定

  • worst-case更可控


❌ 缺点

  • 插入更慢

  • 删除复杂

  • 需要记录探测距离


✔ 复杂度

平均:

复制代码
O(1)

最坏查找:

复制代码
O(log N)(比线性更稳定)

十、考试最重要对比

方法 插入 查找 特点
Linear probing O(1)均摊 O(1)均摊 一次聚集严重
Quadratic probing O(1)均摊 O(1)均摊 改善聚集
Double hashing O(1) O(1) 最均匀
Robin Hood 稍慢 更稳定 降低方差

⭐ 三、Robin Hood一句话

用"交换机制"均衡探测距离,减少查找波动


⭐ 四、核心对比

Rehashing = 扩容恢复O(1)

Robin Hood = 优化分布稳定性

Rehashing解决"太满",Robin Hood解决"探测不均"