Java Arrays.hashcode()的hashcode实现是否均匀分布

时间:2013-09-13 14:01:01

标签: java arrays algorithm hash hashcode

我查看了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。

3 个答案:

答案 0 :(得分:5)

为什么要使用素数31?

这可以分为两部分?

  
      
  1. 为什么是素数?
  2.   

在这里,我们需要了解我们的目标是为对象获取唯一 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这样的小素数可能导致更多的碰撞而不是更大的素数(特别是如果被散列的值不是很好地分配开始),那么你可以选择一个如果你发现表现不如你想的那么好,那就更大了。