【问题标题】:Question about GetHashCode implementation关于GetHashCode实现的问题
【发布时间】:2026-01-04 07:40:01
【问题描述】:

http://msdn.microsoft.com/en-us/library/system.object.gethashcode(VS.80).aspx 说:

为了获得最佳性能,哈希函数必须为所有输入生成随机分布。

它对性能有任何影响吗?或者可以使用不给出“随机分布”但不会导致更多冲突的函数(如 return this.Id)?

【问题讨论】:

    标签: .net performance clr


    【解决方案1】:

    return this.Id 通常没问题(特别是如果Id 是不可变且唯一的) - 主要思想是避免冲突。但是,还要考虑待处理的数据 - 在您尚未保存的 27 行中,Id 是什么?

    还要注意GetHashCodeEquals 实现must agree

    【讨论】:

      【解决方案2】:

      使用 this.Id 通常没问题。基础是您不希望在同一个 bucket 中出现太多冲突。桶号通常通过获取哈希码并将其视为“mod x”来获得,其中 x 是哈希表中桶的数量,通常是素数(或可能的素数)。

      如果您只是使用递增的 ID(1、2、3、4...),就桶分布而言,这最终会变得非常随机。仅当您的 ID 遵循的模式很可能为您需要担心的大量条目提供相同的存储桶编号时。

      【讨论】:

        【解决方案3】:

        似乎措辞不佳......我认为他们的意思是哈希码应该“均匀分布”在所有可能的int值(如果我错了,请.net专家纠正我),这将帮助减少碰撞。

        这是一个例子:假设我所有的哈希码都在 1 到 10 的范围内。如果我要使用哈希码来计算数组长度为 100 的数组索引,那么我最多只能得到 10 个不同的索引。这意味着我的数组利用率很低,我会遇到很多冲突。

        【讨论】:

        • 在同一个小范围内有很多哈希码会是一个问题 - 但是 [1-100](每个数字一次)与 100 个值均匀分布在所有值上一样好。
        • 我认为如果您使用“低阶”位作为索引(如您的答案),这是正确的。如果我使用“高阶”位,那我就不会做得那么好。
        • 事实上,它可能会更好......通过密集分布,您可能会在桶之间获得合理的分布。如果您对稀疏(但等间距)分布不走运,您可以将所有数据放在一个存储桶中。不过,这是一个极端情况——因为它会在存储桶调整大小后修复。
        • @Marc:在 Jon 的 cmets 中,我认为这取决于您如何将哈希码转换为索引。
        • 注意 int.GetHashCode() 是“return this;”,很多东西都是用 int...
        【解决方案4】:

        它可能会影响例如。根据高位散列​​到桶中的散列表(不常见)。此外,例如,如果您的 id 都可以被 4 整除,那么这可以使散列到存储桶 hash_code%buckets 的哈希表仅使用每四个存储桶。

        【讨论】:

        • 注意 int.GetHashCode() 是“return this;”,很多东西都是用 int...
        【解决方案5】:

        我更喜欢使用

        this.Id.GetHashCode();
        

        我认为与直接使用 Id 相比,这更有可能正确分配哈希值。

        【讨论】:

        • 好吧,Id 很可能是一个 int - 而 int.GetHashCode() 是 return this;...
        • @Marc,当然,但我们不应该关心 id 类型的实现细节。所以,“id.GetHashCode()”和“id”实际上是一样的,原理上是不同的。