我查看了Arrays.hashCode(char[] c)
的源代码
我并不是很确定它适用的算法在所有情况下都能很好地工作。
public static int hashCode(int a[]) {
if (a == null)
return 0;
int result = 1;
for (int element : a)
result = 31 * result + element;
return result;
}
这里实现的散列函数是否真正均匀地分配了所有输入数组。为什么我们在这里使用prime 31。
答案 0 :(得分:5)
为什么要使用素数31?
这可以分为两部分?
- 为什么是素数?
醇>
在这里,我们需要了解我们的目标是为对象获取唯一 HashCode,这将帮助我们在O(1)时间内找到该对象。
这里的关键词是唯一。
素数
Primes是唯一的数字。它们的独特之处在于它的产品 与任何其他数字相关的素数最有可能是唯一的(不是 由于一个素数的事实,因为当然的素数本身是独一无二的 用来组成它。此属性用于散列函数。
为什么编号31?
来自 Effective Java
它也是一个小于2的幂,它允许按位 优化
这是完整的引用,
第9项中的:始终覆盖 重写equals:
时的hashCode选择值31是因为它是一个奇数素数。如果它是均匀的 乘法溢出,信息将丢失,如 乘以2相当于移位。使用的好处 素数不太清楚,但它是传统的。
31的一个很好的属性是乘法可以用a代替 shift(§15.19)和减法以获得更好的性能:
31 * i ==(i<< 5) - i现代VM进行这种优化 自动。
虽然此项中的配方产生相当好的散列函数, 它不会产生最先进的哈希函数,也不会产生Java 平台库提供了1.6版本的哈希函数。 编写这样的哈希函数是一个研究课题,最好留给 数学家和理论计算机科学家。
也许稍后发布的平台将提供最先进的技术 其类和实用程序方法的哈希函数允许平均值 程序员构造这样的哈希函数。在此期间, 这个项目中描述的技术应该适合大多数人 应用
这是一个非常Good source.
答案 1 :(得分:1)
选择值31是因为它是奇数素数。如果它是偶数并且乘法溢出,则信息将丢失,因为乘以2相当于移位。使用素数的优势不太明显,但它是传统的。 31的一个很好的特性是乘法可以用移位和减法代替以获得更好的性能:31 * i ==(i <&lt; 5) - i。现代虚拟机会自动执行此类优化。
答案 2 :(得分:1)
请参阅此帖子:Why does Java's hashCode() in String use 31 as a multiplier?
这就是TheEwook的回答来自。
通常,您使用素数是因为它们没有任何因子,并且会分配更好的模N,其中N是您要分组的范围的大小。 31是一个小的奇数素数,所以效果很好。然而,正如您将在互联网上找到的各种来源所表明的那样,像31这样的小素数可能导致更多的碰撞而不是更大的素数(特别是如果被散列的值不是很好地分配开始),那么你可以选择一个如果你发现表现不如你想的那么好,那就更大了。