(d2)散列:排解冲突(2)
第九章 词典 · 知识图解
按 空格/→ 演示下一步
全部页面点击任意一页,跳回舞台从这页播放
(d2)散列:排解冲突(2)
第九章 词典 · 知识图解
平方试探
上一节用线性试探处理冲突,但每次只挪 1 格——连续占用的长块会越滚越大,叫『一次聚集』。本节看一种用平方步长把块切散的策略,以及它带来的新代价。
第 1 次挪 1 个,第 2 次挪 4 个,第 3 次挪 9 个——距离平方增长绕开堵塞带
一利一弊
平方试探跳着找位置(1、4、9…)避开了线性试探的扎堆毛病。但这跳跃本身也带来新麻烦——这就是它的一利一弊。
跳过邻位避开扎堆,但跳太远可能漏掉空座
至多半载
上一页说到平方试探有「找不到空位」的隐患——其实只要控制好一个数字,这个隐患就能彻底避免。它就是装载因子 α。
卖出去的票不超座位一半,任何持票人都能找到位——总有空位
M + Lemda
平方试探虽然避开了「扎堆」,却把装填因子死死压在 0.5 以下,探测序列才兜得回来。要打破这层天花板,得换一个每条记录自带步长的规则——这就是 M + λ。
第一次按票号定位排数,找不到就每次往后挪 λ 排,而不是只挪一排
双蜓点水
前面我们看到 λ 不能太高——因为大家都挤着挪动会形成聚集。有没有办法让每个 key「跳的步子」本来就不同?双散列就是答案。
每个孩子按自己编号跳不同格数,比大家都只挪一格更不容易扎堆
4k + 3
上一页说平方试探「至多半载」——只能探测到一半的槽位。但有个巧办法:只要表长取成 4k+3 的素数,再把试探方向从单向改成 ±i²,就能走遍全表。
原来只往一个方向开(+i²),改造成环后顺逆都能走,所有车位都到得了
双平方定理
上一页我们说,只要表长 M 是 4k+3 形式的素数,平方探测就能覆盖至少一半的槽位——但这是经验直觉还是可证明的事实?这一页把它写成定理。
跳距由完全平方数决定;书架总数是 4k+3 型素数时,跳一半也碰不到重复格
泾渭分明
双平方定理告诉我们 M 取 4k+3 型素数时平方试探能走通;但实际中表长未必总能精挑,于是 M + Λ 成了兜底。两种策略思路截然不同。
同解一道难题:让平方试探走通。一个事前规划、一个临场反应
本节要点
- ✓α 越逼近 0.5,探测长度非线性上升,性能塌陷
- ✓表长取 4k+3 素数可证遍历全表,背后是二次互反律
- ✓次聚束是平方探测的结构性宿命,源于初探位相同的键
- ✓双散列并非万能:h₂ 为零时仍会退化为线性探测
- ✓所有探测法都是探测开销与聚束程度的折中
课后思考
先想,再对。三个问题没有标准答案,参考答案只是抛砖引玉。
参考答案探测序列 ±k² 在表中对称跳跃,负载因子超过 1/2 时,空槽可能落在所有跳跃点的间隙里。
参考答案探测序列可能提早陷入循环,找不到空槽,即便表未满。4k+3 型素数保证前 ⌈M/2⌉ 步覆盖所有槽位。
参考答案平方探测缓解了主聚类,但仍有次聚类,且跳跃会牺牲缓存局部性。冲突少时差别不大,冲突密集时它更稳健。