实现哈希函数有两种基本方法,几乎在每本教科书和CS课程中都有引用:
k mod m
基本上选择m为素数而不是太接近2的幂。大多数教科书和课程都列举了方法1的一些缺点,包括它昂贵且事情取决于m的事实。然而,我从未见过任何教科书或课程提到方法2的单一劣势。
这使方法2更令人满意。此外,方法2可以在现代计算机上非常有效地消除浮点运算。因此看起来方法2看起来是赢家,并且没有人应该谈论方法1.但事实显然并非如此。事实上,我从未见过在任何实际实现中使用方法2。所以它确实有一些缺点。
问题是它们是什么以及为什么方法1被更频繁地使用,尽管它有缺点?
答案 0 :(得分:3)
分区方法与需要主表大小的哈希表算法结合使用 - 例如,使用双哈希或QHash的开放寻址,当你无论如何需要按表大小划分密钥或哈希时得到索引。
当表大小是2的幂时,乘法方法是合适的,然后从散列中获取索引可以实现为按位AND运算,因此通过密钥计算表索引的整个路径,使用乘法散列,是非常快。您可以通过searching for magic constant 2654435769 on Github探索一些实际的实现。
最近有使用MurmurHash3雪崩程序而非乘法方法的趋势:
int hash = key;
hash ^= (hash >> 16);
hash *= 0x85ebca6b;
hash ^= (hash >> 13);
hash *= 0xc2b2ae35;
hash ^= (hash >> 16);
// see this code and the version for 64 bits here:
// https://smhasher.googlecode.com/svn/trunk/MurmurHash3.cpp
因为它只是稍慢一点,但被认为对于错误的密钥分发更加健壮。这就是为什么你可能会错误地(或者说对了?)很少使用乘法方法的印象。