h2(x) = h1(x) ⊕ hash(x’s fingerprint).
我们可以看到,计算 h2(位置2)时,对 x 的 fingerprint 进行了一个 hash 计算。
“指纹”的概念一会再说,我们先关注位置的计算。
上面算法中的异或运算确保了一个重要的性质:位置 h2 可以通过位置 h1 和 h1 中存储的“指纹”计算出来。
说人话就是:只要我们知道一个元素的位置(h1)和该位置里面存储的“指纹”信息,那么我们就可以知道该“指纹”的备用位置(h2)。
因为使用的异或运算,所以这两个位置具有对偶性。
只要保证 hash(x’s fingerprint) !=0,那么就可以确保 h2!=h1,也就可以确保,不会出现自己踢自己的死循环问题。
另外,为什么要对“指纹”进行一个 hash 计算之后,在进行异或运算呢?
论文中给出了一个反证法:如果不进行 hash 计算,假设“指纹”的长度是 8bit,那么其对偶位置算出来,距离当前位置最远也才 256。
为啥,论文里面写了:
因为如果“指纹”的长度是 8bit,那么异或操作只会改变当前位置 h1(x) 的低 8 位,高位不会改变。
就算把低 8 位全部改了,算出来的位置也就是我刚刚说的:最远 256 位。
所以,对“指纹”进行哈希处理可确保被踢出去的元素,可以重新定位到哈希表中完全不同的存储桶中,从而减少哈希冲突并提高表利用率。
然后这个 hash 函数还有个问题你发现了没?
它没有对数组的长度进行取模,那么它怎么保证计算出来的下标一定是落在数组中的呢?
这个就得说到布谷鸟过滤器的另外一个限制了。
其强制数组的长度必须是 2 的指数倍。
2 的指数倍的二进制一定是这样的:10000000...(n个0)。
这个限制带来的好处就是,进行异或运算时,可以保证计算出来的下标一定是落在数组中的。
这个限制带来的坏处就是:
布谷鸟过滤器:我支持删除操作。
布隆过滤器:我不需要限制长度为 2 的指数倍。
布谷鸟过滤器:我查找性能比你高。
布隆过滤器:我不需要限制长度为 2 的指数倍。
布谷鸟过滤器:我空间利用率也高。
布隆过滤器:我不需要限制长度为 2 的指数倍。