【发布时间】:2017-08-18 10:40:12
【问题描述】:
看着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 的常量值增加最终的 has 值,这将推广到 i*23^(字段数)。
那么这有什么帮助呢?如果 f1、f2、f3 都为 0,那么如果最终哈希为 0 是否有问题?它是非零的东西会更好吗?我唯一的想法是,出于某种原因,使用哈希值的字典或哈希集之类的东西的实现更喜欢非零值,但我想不出这个原因可能是什么。或者其他的东西当然是这些东西有点神秘,所以人们使用经过试验和测试的东西,所以即使没有理由,初始值也会被传播。
我尝试查找一些 microsoft 哈希码,但我发现所有这些都使用外部代码来计算它们(对象、字符串)或者有些特殊(在匿名对象上的 GetHashCode 实现种子哈希码是基于属性名称的匿名对象是不同的,因为它不是一个恒定的初始值)。
所以总结一下为什么哈希码实现中的初始常量值?
编辑:Why use a prime number in hashCode? 被建议为重复,该网站希望我编辑我的问题以解释为什么它不是重复的...我承认素数被用作乘数在计算中,我明白为什么会这样。这个问题明确地是关于在哈希码算法中用作初始种子的。建议的副本没有明确说明素数的用途,但答案都将其用作与该问题无关的乘数。
【问题讨论】:
-
我应该注意作为一个帖子脚本,虽然这个问题被标记为 c#,但它可能更普遍地适用。我把那个语言标签放在上面的唯一原因是我不知道其他语言是否确实暗示了同样的事情,所以我想我会把它保留在我正在查看的具体示例中。如果有其他语言经验的人想扩大范围,请随意。