【问题标题】:Will this hash function collide unusually frequently?这个哈希函数会不会异常频繁地发生碰撞?
【发布时间】:2011-09-11 06:16:09
【问题描述】:

我有以下代码来生成对象的哈希:

public int GetHashCode(MyType obj)
{
   return (obj.Prop1.GetHashCode() + obj.Prop2.GetHashCode() + obj.Prop3.GetHashCode()).GetHashCode();
}

即我添加了所有属性的哈希码,然后对其进行哈希处理。

在审查中,一位同事建议这将过于频繁地发生冲突。我不确定这是不是真的,因为:

  1. 鉴于哈希码在正数和负数中以相同的频率被选择并且它们环绕,我认为我们没有获得任何关于这些数字总和的可能性而不是数字本身的额外信息
  2. 如果它们的总和是非随机的,哈希码旨在使“靠近”的数字变得“相距很远”,因此将非均匀分布的值输入函数不应该是问题

谁是正确的?

它在 C# 中,以防答案是特定于语言的。

【问题讨论】:

  • 你同事的原因是什么?

标签: c# hash hash-collision hash-code-uniqueness


【解决方案1】:

是的。

假设 Prop1、Prop2 等的类型为 int。通常只使用较低的整数范围。您的求和方法将比必要的更频繁地发生冲突。

7 的 HasCode 为 7,这在自行对 int 进行散列时非常有意义。但是使用您的代码,元组<7, 3><3, 7><8, 2> 都将具有相同的哈希。与简单的异或而不是加法相同。

常见的方法是添加一些(质数)数字并移位:

public int GetHashCode(MyType obj)
{
  int hash = 0;
  unchecked
  {         
     hash += 19 * obj.Prop1.GetHashCode();
     hash += 31 * obj.Prop2.GetHashCode();
     hash += 37 * obj.Prop3.GetHashCode();
  }
  return hash;
}

数字 19、31、37 并不太重要。如果您愿意,可以使用 OR 或 XOR 代替 +

【讨论】:

  • 质数很好,比移位更可取,因为简单的分箱算法很可能只取 HashCode 的低 N 位;如果属性被转移,它们最终可能会被完全忽略。
【解决方案2】:

XORing 会更好:

public int GetHashCode(MyType obj)
{
   return obj.Prop1.GetHashCode() ^ 
          obj.Prop2.GetHashCode() ^ 
          obj.Prop3.GetHashCode();
}

【讨论】:

  • 参见 Henk Holterman 的推理。如果某些属性的 GetHashCode 不使用整个范围,则与班次混合应该提供更好的分布...
【解决方案3】:

您可以使用修改后的 FNV HashCode 生成器,已回答了一个非常相似的问题(由我) here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-28
    • 2017-08-16
    • 2012-04-30
    • 1970-01-01
    • 2010-11-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多