本文主要对 Cuckoo Hashing (布谷鸟散列) 的基本原理进行描述
原理
综述
- 维护两个表 T 1 , T 2 T_1,T_2 T1,T2,每个表都有 m m m 个元素
- 选择两个哈希函数 h 1 h_1 h1 和 h 2 h_2 h2,这两个哈希函数将输入空间 Ω \Omega Ω 映射到 0 ∼ m − 1 0\sim m-1 0∼m−1
- 对于元素 x ∈ Ω x\in \Omega x∈Ω, x x x 要么存储在 T 1 T_1 T1 的位置 h 1 ( x ) h_1(x) h1(x) 处,要么存储在 T 2 T_2 T2 的位置 h 2 ( x ) h_2(x) h2(x) 处
查询&删除
Cuckoo Hashing 查询操作时间复杂度为 O ( 1 ) O(1) O(1),因为每个元素只可能存储在两个位置
Cuckoo Hashing 删除操作时间复杂度为 O ( 1 ) O(1) O(1),因为每个元素只可能存储在两个位置
插入
- 为了插入一个元素 x x x,将其插入到 T 1 T_1 T1
- 如果 T 1 T_1 T1 的位置 h 1 ( x ) h_1(x) h1(x) 处是空的,那就把 x x x 插入到该位置即可
- 如果 T 1 T_1 T1 的位置 h 1 ( x ) h_1(x) h1(x) 已经被元素 y y y 占用了,那就牺牲掉 y y y,把 x x x 插入到该位置,然后再尝试把 y y y 插入到 T 2 T_2 T2 的位置 h 2 ( y ) h_2(y) h2(y) 处
- 类似地,如果 T 2 T_2 T2 的位置 h 2 ( y ) h_2(y) h2(y) 处是空的,就把 y y y 插入到该位置即可;如果 T 2 T_2 T2 的位置 h 2 ( y ) h_2(y) h2(y) 处已经被元素 z z z 占用了,先把 y y y 插入到该位置,然后尝试把 z z z 插入到 T 1 T_1 T1 的位置 h 1 ( z ) h_1(z) h1(z) 处。依此类推,直到所有的元素都插入成功了。
- 插入操作可能会陷入死循环,比如考虑三个元素 A ,B和C, h 1 ( A ) = 0 , h 2 ( A ) = 1 , h 1 ( B ) = 0 , h 2 ( B ) = 1 , h 1 ( C ) = 0 , h 2 ( C ) = 1 h_1(A)=0,h_2(A)=1,h_1(B)=0,h_2(B)=1,h_1(C)=0,h_2(C)=1 h1(A)=0,h2(A)=1,h1(B)=0,h2(B)=1,h1(C)=0,h2(C)=1,假设 A 已经存储在 T 1 T_1 T1 的位置0处了,B 已经存储在 T 2 T_2 T2 的位置1处了,现在要插入 C,首先 C 会插入 T 1 T_1 T1 的位置0处,然后 A 被牺牲,因此 A 插入 T 2 T_2 T2 的位置1处,然后 B 被牺牲,因此接下来会将 B 插入 T 1 T_1 T1 的位置0处,此时 C 被牺牲,然后 C 会被插入 T 2 T_2 T2 的位置1处,依此往复,陷入死循环
- 为了解决该问题,可以考虑设置一个阈值,当循环的次数大于该次数时,认为此时发生了死循环,此时选择新的 h 1 h_1 h1 和 h 2 h_2 h2,然后将所有的元素通过使用这两个新的哈希函数重新插入表中
- Cuckoo Hashing之所以这样命名,是因为上述插入如果发生冲突,其处理该冲突的过程类似于:布谷鸟不自己筑巢,而是在别的鸟巢里面孵化鸟蛋,孵化出的幼鸟会将别的鸟蛋挤出
Cuckoo Graph
简介
为了方便研究Cuckoo Hashing,尤其是上面的插入操作,引入Cuckoo graph
Cuckoo graph 是从哈希表导出的二部图,下图为一个实例
每条边上有一个元素,可以理解为每条边代表一个元素,该边连接了该元素在两个表中可能存放的位置;每次插入一个元素会往其中引入一条边
一个插入操作会经历cuckoo graph中的一系列边,下面考虑两个实际的例子
-
往其中插入88,首先引入一个边,该边连接了88在两个表中可能的位置,如下图所示,下图中标蓝路径是插入88后,各个元素不断移动位置所经历的边,如果不明白这个意思,建议复现一下插入88的完整过程,这样就可以理解了
-
接下来往其中插入4,首先引入一个边,该边连接了4在两个表中可能的位置,如下图所示,该插入操作会导致死循环,下图红色路径显示了各个元素不断移动位置所经历的边
定理
定理1:将 x 插入到 Cuckoo 哈希表中,如果包含 x 的连通分量有两个或更多循环,则插入失败。
证明:cuckoo graph中每条边可以代表一个元素,每个节点代表哈希表中的一个位置
如果在该连通分量中有k个节点,由于该连通分量至少有2个循环,因此边的个数至少为k+1,k+1个元素(边)不可能放入k个位置(节点)中,因此插入失败
定理2:如果 x 被插入到一个 cuckoo 哈希表中,如果包含 x 的连通分量不包含循环或只有一个循环,则插入成功
定理3:如果将 x 插入到具有 k 个节点的连通分量中,则插入过程最多进行 2k 次位移。
术语:
- A tree is an undirected, connected component with no cycles.
- A unicyclic component is a connected component with exactly one cycle.
- A connected component is called complex if it’s neither a tree nor unicyclic.
定理4:Cuckoo hashing fails iff any of the connected components in the cuckoo graph are complex.
To analyze cuckoo hashing, we’ll do the following.
- First, we’ll analyze the probability that a connected component is complex.
- Next, under the assumption that no connected component is complex, we’ll analyze the expected cost of an insertion.
- Finally, we’ll put the two together to complete the analysis