我试图将大约6400万个64位唯一无符号整数散列到1.28亿个桶(27位宽地址)。我尝试了Bob Jenkin的HashLittle和Murmur哈希(这两个哈希函数都提供了32位哈希值,我将其屏蔽以获得27位地址)。在这两种情况下,它导致大约22%的碰撞,最终只占据了37%的水桶。这是预期还是我做错了什么?我期待更少的碰撞和更好的铲斗占领。
答案 0 :(得分:6)
使用基于http://en.wikipedia.org/wiki/Poisson_distribution的近似值,它看起来比我预期的要差一些。如果桶中的预期条目数是1/2,我预计0个条目的概率大约是exp(-0.5)= 0.607,并且桶中1个条目的概率大约是这个的一半,或0.303。这使得存储桶具有两个或更多条目的概率为0.09。
你的整数是否都是独一无二的?如果没有,您是否将重复值计算为导致哈希冲突?
在有利的情况下,您可以选择一个哈希函数,以便给出随机期望的FEWER冲突。有时hash(x)= x%p,其中p是素数,将实现此目的。
答案 1 :(得分:1)
如果你想得到随机但可重复的"结果 - 即使对于故意困难的输入也具有最佳的最坏情况碰撞率* - 您可以简单地创建一个表格,如:
uint32_t r[8][256];
使用8kb的随机数据填充它 - 您可以谷歌搜索一个包含随机数据的网站,并将其重新格式化以包含在您的源中或在运行时从文件加载。
(*) - 只要输入不是由知道您的随机数据的恶意软件创建的。
然后像这样哈希:
uint32_t hash(uint64_t n)
{
unsigned char* p = (unsigned char*)&n;
return r[0][p[0]] ^ r[1][p[1]] ^ r[2][p[2]] ^ r[3][p[3]] ^
r[4][p[4]] ^ r[5][p[5]] ^ r[6][p[6]] ^ r[7][p[7]];
}
当然,更好的最坏情况碰撞通常与更好的实际性能完全不同 - 很大程度上取决于您的数据集和硬件 - 所以如果您真正关心的话,它只是一个基准测试的东西。做基准简单传递。使用素数桶是非常好的做法,但根据您的哈希表可能会很棘手 - 例如某些实现可能会将任何调整大小请求舍入为2的幂。