首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >快速简单的哈希码组合

快速简单的哈希码组合
EN

Stack Overflow用户
提问于 2009-10-29 21:53:21
回答 10查看 55.2K关注 0票数 102

人们能推荐快速简单的方法来组合两个对象的哈希码吗?我不太担心碰撞,因为我有一个哈希表,它将有效地处理这个问题,我只想尽快生成代码。

环顾四周,网络上似乎有几个主要的候选人:

  1. XORing
  2. 素数乘法的XORing
  3. 简单的数字操作,如乘法/除法(带有溢出检查或环绕)
  4. 生成字符串,然后使用String类Hash Code方法

人们会推荐什么?为什么?

EN

回答 10

Stack Overflow用户

回答已采纳

发布于 2009-10-29 22:11:04

我个人要避免异或--这意味着任何两个相等的值都会导致0-所以散列(1,1) ==散列(2,2) ==散列(3,3)等等,也就是散列(5,0) ==散列(0,5)等等。我故意用它来设置散列--如果你想散列一系列商品,而你不关心订单,那就太好了。

我通常用:

代码语言:javascript
运行
复制
unchecked
{
    int hash = 17;
    hash = hash * 31 + firstField.GetHashCode();
    hash = hash * 31 + secondField.GetHashCode();
    return hash;
}

这就是乔希·布洛赫在有效Java中建议的形式。上一次我回答一个类似的问题时,我找到了一篇详细讨论这一问题的文章-- IIRC,没有人真正知道它为什么工作得很好,但它确实有效。它也很容易记住,很容易实现,也很容易扩展到任意多个领域。

票数 155
EN

Stack Overflow用户

发布于 2018-08-06 22:35:38

如果您正在使用.NET Core2.1或更高版本或.NET Framework4.6.1或更高版本,请考虑使用System.HashCode结构来帮助生成复合哈希代码。它有两种操作方式:添加和组合。

一个使用Combine的示例,它通常更简单,最多可用于八个项:

代码语言:javascript
运行
复制
public override int GetHashCode()
{
    return HashCode.Combine(object1, object2);
}

使用Add的一个例子

代码语言:javascript
运行
复制
public override int GetHashCode()
{
    var hash = new HashCode();
    hash.Add(this.object1);
    hash.Add(this.object2);
    return hash.ToHashCode();
}

优点:

  • .NET本身的一部分,如.NET Core2.1/.NET标准2.1 (尽管,请参阅下面的con )
    • 对于.NET Framework4.6.1及更高版本,可以使用Microsoft.Bcl.HashCode NuGet包来支持这种类型。

  • 基于作者和评审员在将其合并到corefx回购系统中之前所做的工作,看起来具有良好的性能和混合特性。
  • 自动处理空
  • 采用IEqualityComparer实例的重载

缺点:

票数 86
EN

Stack Overflow用户

发布于 2015-11-30 19:25:00

虽然Jon的答案中概述的模板作为一个散列函数族通常工作得很好,但常量的选择是很重要的,答案中提到的17的种子和31的因子对于普通用例根本不起作用。在大多数用例中,哈希值比int.MaxValue更接近于零,并且联合散列的项的数量是几十个或更少。

对于散列整数元组{x, y},其中-1000 <= x <= 1000-1000 <= y <= 1000,它的极差碰撞率几乎为98.5%。例如,{1, 0} -> {0, 31}{1, 1} -> {0, 32}等,如果我们将覆盖范围扩大到包括3 <= n <= 25的n元组,那么它就不会那么糟糕了,碰撞率约为38%。但我们可以做得更好。

代码语言:javascript
运行
复制
public static int CustomHash(int seed, int factor, params int[] vals)
{
    int hash = seed;
    foreach (int i in vals)
    {
        hash = (hash * factor) + i;
    }
    return hash;
}

我编写了一个蒙特卡罗抽样搜索循环,用不同的种子值和随机整数i的各种随机n元组上的因子测试了上述方法。允许的范围是2 <= n <= 25 ( n是随机的,但偏向于范围的低端)和-1000 <= i <= 1000。对每个种子和因子对进行了至少1200万次独特碰撞试验。

运行约7小时后,最佳结合点为:seed = 1009factor = 9176,碰撞率为0.1131% (种子和因子均限制在4位以下)。在5位和6位数的区域,还有更好的选择。但为了简洁起见,我选择了前4位的表演者,它在所有常见的intchar散列场景中都表现得很好。它似乎也能很好地处理大得多的整数。

值得注意的是,作为种子和/或因素,“成为最佳”似乎并不是良好业绩的一般先决条件,尽管它可能有所帮助。上面提到的1009实际上是素数,但9176不是。在此,我显式地测试了各种变体,其中我将factor更改为9176附近的各种素数(同时离开了seed = 1009),它们的性能都比上面的解决方案差。

最后,我还与一般的ReSharper推荐hash = (hash * factor) ^ i;函数族和上面提到的原始CustomHash()进行了比较,结果非常好。对于一般的用例假设,ReSharper XOR风格的碰撞率似乎在20-30%之间,我认为不应该使用。

票数 62
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1646807

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档