形式陈述
Cuckoo Hashing 是哈希表理路哈希表Hash table用哈希函数把键映射到桶并处理冲突的字典结构。中的开放定址理路开放定址哈希open addressing · closed hashing把键直接存放在表数组槽位中的哈希表示;经典探测序列法与允许重定位的变体使用不同的查找不变量。方案:每个键只允许落在少数候选位置,查询因此只检查常数个槽位,插入则通过重定位链恢复这一位置约束。
两位置不变量
两张表分别有 个槽,两个函数给键 候选位置 与 。即使下标相同,两张表的槽也是不同位置。查询正确性只依赖下面的位置不变量;插入的概率界则需要比仅控制键对碰撞的通用哈希理路通用哈希Universal hashing · Universal hash family从函数族随机选择哈希函数,使任意预先固定的不同键对以至多 1/m 的概率碰撞。更强的随机性条件。每个键恰好存于二者之一;在哈希求值与键比较均为常数成本的模型下,查找只检查两处,最坏 。插入先检查键是否已存在:集合模式直接返回,映射模式覆盖其关联值并保留位置。只有新键才放入一个候选槽,若占用就踢出旧键,旧键转到自己的另一位置;达到预先规定的踢出步数阈值后,重新选择哈希函数并重建。单环分量仍可能放置成功,不能把图中出现任意环都当作失败。
Cuckoo 图刻画
沿用图理路有限简单无向图Graph · Finite simple undirected graph · 图由有限顶点集与无序二元顶点子集组成的边集所确定的简单无向图。的顶点与边语言,把两张表的槽分作二分的两侧,每个不同键对应连接两个候选槽的一条带身份的边。这里要扩展为允许平行边的二分多重图:不同键可以拥有相同候选对,不能把它们合并成简单图的一条边。为每条边选择一个端点存放,且每顶点容量一;经典单槽模型可成功放置,当且仅当每个连通分量的边数不超过顶点数,即分量至多含一个环。树分量沿路径定向即可,双环分量必有某槽承担两键。
直觉
每个键像一条连接两个候选槽的边,选择存储位置就是把这条边定向到一个端点。踢出链沿着当前定向寻找可改道的路径;若某个分量的边比槽还多,无论从哪一键开始踢都不可能成功,循环只是容量障碍在执行过程中的表现。
Cuckoo 哈希的 kick-out 链
例子与边界
踢出路径例子
新键 占用 并踢出 , 转到 又踢出 ;若 的另一槽为空,整条交替路径完成。若路径回到已经出现的状态,继续踢只会循环,必须 rehash,而不是声称插入仍为最坏常数。
概率与装载边界
原论文期刊版的期望摊还 更新界选取如下条件:键占一个 RAM 字,输入操作序列与算法的随机选择独立;固定 ,维持每张表容量 ,并以几何扩缩容保持线性空间。两个函数独立抽取且可在常数时间求值。对充分大的规模,插入最多执行 轮,每轮依次尝试两张表;自上次重哈希开始累计至多 次插入后,还要主动重哈希。常数规模单独处理。
该分析使用的哈希族构造,在任意固定的至多 个相关键上,以 的概率提供 阶独立均匀输出,其中 为固定常数;构造失败事件另计入时间分析。充分大时 ,足以分析一次受限踢出过程涉及的键。这个构造条件与定期换函数共同限定了同一哈希对服务的键集;普通通用碰撞界只控制键对,不能替代它。
这里总装载率是 。桶化 cuckoo、更多候选和 stash 有各自的阈值与查询契约。查询的常数最坏界针对已经构造好的顺序表;Las Vegas 重建通过重试保持结果正确,运行时间随机。
推论与应用
候选位置由随机哈希函数决定,插入失败概率和重哈希次数因此属于随机化算法理路随机化算法Randomized algorithm把随机比特作为额外输入并分析输出正确率或运行时间分布的算法。分析。查询的常数探测是条件性的:它依赖当前表已经成功构造,并不消除构造阶段的随机失败事件。
Rehash 的摊还语义
达到踢出阈值或本轮哈希对的 次插入上限时,都给全部现存键及尚未安置的键换一对函数,重置本轮计数并重新构建;重建中的插入也从这次重建开始计数,失败则重新开始。原论文在上述条件下证明,普通踢出过程的期望长度为 ,一次插入因超限而触发重建的概率为 ,一次完整重建的期望成本为 。
失败触发的额外期望成本因此为 ;定期重哈希的成本分摊到该轮插入,同样为 。几何扩缩容再单独摊还,得到期望摊还常数更新。主动重哈希所在的那一次操作仍可能花费线性时间,故这项保证是对操作序列的成本记账。
这个结论要求失败时更换函数,而不是沿同一环从另一个起点继续踢。扩容也改变图顶点数和阈值。若系统要求每次插入最坏延迟,需要增量 rehash、stash 或 deamortization,并重新说明查询要检查哪些旧/新位置。
失败分量怎样被识别
设第一张表的槽为 ,第二张表的槽为 。四个不同键的候选边为 、、、,构成一个四环,可依次把四条边放在 。再加入第五个键,其候选仍为 ,就得到允许平行边的二分图分量:5 条边争用 4 个槽,任何放置都必然失败。两表模型不会出现三角形;不同键拥有同一对候选则完全可能。
实现可按以下顺序处理:
- 限制一次踢出的最大步数,并记录本轮访问状态;
- 超限后把新键和被踢出的键一起保留在临时区,不能丢失;
- 抽取新哈希函数,从空表重插全部键;
- 若仍失败则重试,达到负载阈值时先扩容;即使一直成功,也在同一哈希对累计 次插入后主动重哈希。
查找只检查两个槽的最坏 与插入的期望摊还 是两种不同保证。若加入 stash,查询还必须检查 stash;若后台增量重建,查询需同时检查新旧表,不能继续声称接口完全未变。
参考资料
- Rasmus Pagh、Flemming Friche Rodler,Cuckoo Hashing, Journal of Algorithms 51(2), 2004,pp. 122–144;期刊版公开副本,§1.1、§2–2.3:字长键模型、哈希族、定期重哈希和期望摊还分析。
- Michael Mitzenmacher, Some Open Questions Related to Cuckoo Hashing, ESA, 2009.