为什么在hashCode中使用质数?


173

我只是想知道为什么在类的hashCode()方法中使用质数?例如,当使用Eclipse生成我的hashCode()方法时,总是使用素数31

public int hashCode() {
     final int prime = 31;
     //...
}

参考文献:

这是有关Hashcode的一个很好的入门,以及有关我发现的哈希如何工作的文章(C#,但这些概念是可转让的): Eric Lippert的GetHashCode()准则和规则




1
请检查我在stackoverflow.com/questions/1145217/上的答案。它与域(不是环!)上的多项式的性质有关,因此与质数有关。
TT_

Answers:


103

因为您想要乘以的数量以及要插入的存储桶的数量具有正交素数分解。

假设要插入8个桶。如果您要乘以的数字是8的倍数,则插入的存储桶将仅由最低有效项决定(该数字完全不相乘)。类似的条目将发生冲突。不适用于哈希函数。

31是足够大的素数,因此不可能被它整除(实际上,现代的Java HashMap实现将存储桶的数量保持为2的幂)。


9
然后,乘以31的哈希函数将无法最佳执行。但是,考虑到31作为乘法器的普遍性,我认为这样的哈希表实现设计不良。
ILMTitan

11
因此,基于以下假设选择31:哈希表实现者知道哈希码中通常使用31?
郭富城

3
基于大多数实现都具有相对较小质数的因式分解的思想来选择31。通常是2s,3s和5s。它可能从10开始并在变得太满时增长3倍。大小很少是完全随机的。即使是这样,拥有良好同步的哈希算法也算不上30/31。正如其他人所说,这可能也很容易计算。
ILMTitan

8
换句话说...我们需要了解有关输入值集和规则集的规律性,以便编写一个旨在去除它们的规则性的函数,以便使集合中的值不会发生冲突哈希桶。通过质数乘/除/模实现此影响,因为如果您具有带有X项的LOOP并且在循环中跳过Y空间,那么在X成为Y的因数之前,您永远不会回到同一位置由于X通常是偶数或2的幂,因此您需要Y为质数,因此X + X + X ...不是Y的因数,所以31年!:/
Triynko 2010年

3
@FrankQ。这是模块化算术的本质。 (x*8 + y) % 8 = (x*8) % 8 + y % 8 = 0 + y % 8 = y % 8
ILMTitan
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.