为什么在GetHashCode实现中使用初始素数?

时间:2017-08-18 10:40:12

标签: c# hashcode

看着What is the best algorithm for an overridden System.Object.GetHashCode?我很震惊,在许多建议类型为hash = hash*(prime) + item.GetHashcode()的哈希码的答案中,哈希的值最初被播种到另一个素数而不是0。

我理解计算部分互质数的原因在很多方面都很有用。

我不明白为什么哈希首先被初始化为非零数字。

看一下精确的例子:

int hash = 17;
hash = hash * 23 + field1.GetHashCode();
hash = hash * 23 + field2.GetHashCode();
hash = hash * 23 + field3.GetHashCode();
return hash;

简而言之,让field1.GetHashCode()用f1表示(对其他人来说等等),初始哈希值为i,然后给出:

int hash = i;
hash = i * 23 + f1;
hash = (i * 23 + f1)* 23 + f2;
hash = ((i * 23 + f1)* 23 + f2)* 23 + f3;

扩展最后一行的括号:

hash = (i*23*23 + f1*23 + f2)* 23 + f3;
hash = i*23*23*23 + f1*23*23 + f2*23 + f3;

因此我们可以看到初始哈希值的唯一影响是将最终的值增加一个常量值i * 23 * 23 * 23,这将推广到i * 23 ^(字段数)。< / p>

那么这有什么用呢?如果f1,f2,f3全为0,如果最终散列为0,则会出现问题吗?它是不是更好的非零?我唯一的想法是,使用哈希值的字典或散列集之类的实现由于某种原因更喜欢非零值,但我不能想到这个原因可能是什么。或者其他事情当然是这些东西有点神秘,所以人们使用经过试验和测试的东西,所以即使没有理由,初始值也会传播。

我尝试查找一些微软的哈希码,但是我发现它们都使用外部代码来计算它们(对象,字符串)或者稍微有点特殊(匿名对象上的GetHashCode实现基于哈希码的属性名称生成哈希码)匿名对象是不同的,因为它不是一个恒定的初始值。)

总结为什么哈希码实现中的初始常量值?

修改Why use a prime number in hashCode?被建议重复,网站要我编辑我的问题以解释为什么它不重复...我已经承认素数被用作计算中的乘数​​,我明白为什么会这样。这个问题明确地用作哈希码算法中的初始种子。建议的副本没有明确说明素数用于什么,但答案都解决了将其用作与此问题无关的乘数因素。

1 个答案:

答案 0 :(得分:2)

这个问题有some good answers on the Computer Science SE。简而言之:初始常量是根据可能需要不同数量输入的哈希来改编的,而你在这个例子中并不重要。