【问题标题】:Isn't 'int GetHashCode' a bit short-sighted?'int GetHashCode' 是不是有点短视?
【发布时间】:2011-01-05 02:18:08
【问题描述】:

鉴于 .Net 能够通过 IntPtr 检测位数(尽管通过反射器查看大量它被标记为不安全 - 可惜)我一直认为 GetHashCode 返回一个 int 可能是短视的。

我知道,最终通过一个好的散列算法,Int32 提供的数十亿个排列绝对足够,但即便如此,可能的散列集越窄,散列键查找就越慢,因为需要更多的线性搜索。

同样——我是唯一一个觉得这很有趣的人吗:

struct Int64{
  public override int GetHashCode()
  {
    return (((int) this) ^ ((int) (this >> 0x20)));
  }
}

而 Int32 只返回 this

如果 IntPtr 由于性能问题而无法使用,那么实现 IEquatable 等的 IHashCode 可能会更好?

随着我们的平台在内存容量、磁盘大小等方面变得越来越大,32 位哈希足够的日子肯定已经屈指可数了吗?

或者仅仅是通过接口抽象散列或根据平台调整散列大小所涉及的开销超过任何潜在的性能优势?

【问题讨论】:

    标签: .net hashcode


    【解决方案1】:

    确实意识到GetHashCode 返回的哈希码用于在哈希表中寻址?使用更大的数据类型将是徒劳的,因为无论如何所有哈希表都较小。额外的信息只会被浪费,因为它不能被充分利用。

    常见的哈希表有几千到几百万个条目。一个 32 位整数足以覆盖这个索引范围。

    【讨论】:

    • 嗯 - 这不太正确 - 2,034,242,111 的哈希码不会用作索引。与数组不同,没有其他内存限制哈希表的大小 - 从理论上讲,它没有理由不能拥有 100 亿个元素,即使使用 32 位哈希也是如此。这只是内存限制。带上一台有几百 GB 内存(好吧,假设是 TB)的机器,我们可以用如此巨大的哈希表填充它。但是,您是否会 - 或创建其他结构 - 是另一回事!
    • @Andras:这与普通数组有何不同(提示:不是)。是的,您可以拥有 100 亿个元素 - 就像普通数组一样,但它无法在 任何 当前架构上扩展。为能够处理 1 TeB 主内存的全球 one 机器卷积整个 .NET 架构对我来说听起来不是一个好的折衷方案。关键是:架构必然涉及权衡,将地址大小加倍可能很重要。
    • @KonradRudolph,但是您确实明白,具有更大范围的哈希函数将提供更好的抗碰撞性,即更少的 .Equals 调用。当然哈希,可能是 16 位或 32 或 64 是 `mod some prime greater than capacity`,这里哈希函数的分布仍然很重要。
    • @SebastianGodelet 除非您的哈希表有 > 2^32 个桶(非常罕见!),否则它不会发挥任何作用。请参阅我之前的评论,这点大致相同。
    • @Sebastian 您链接的文章与哈希表完全无关。它只表明作者从未听说过birthday paradox,因此错误地使用了哈希码。你说得对,减少冲突是一个好的哈希表的关键,但就像我之前说的,我们只关心 final 哈希中的冲突(即在缩小到哈希表大小之后),而不是初步哈希的冲突。 32 位散列会比 64 位散列更频繁地发生冲突,但我们在散列表中使用 noither
    【解决方案2】:

    Int64 散列函数用于确保考虑所有位 - 所以基本上它是将前 32 位与后 32 位进行异或运算。我真的无法想象一个更好的通用型。 (截断为 Int32 是不好的——你怎么能正确地散列低 32 位全为零的 64 位值?)

    如果 IntPtr 被用作散列返回值,那么代码将必须有条件分支(是 32 位吗?是 64 位吗?等等),这会减慢散列函数的速度,从而破坏整点。

    我想说,如果您有一个实际上有 20 亿个桶的哈希表,那么您可能正处于编写整个自定义系统的阶段。 (可能数据库会是更好的选择?)在那个大小下,确保桶被均匀填充将是一个更紧迫的问题。 (换句话说,一个更好的哈希函数可能会比大量的桶支付更多的红利)。

    如果您确实想要内存中的多 GB 映射,那么没有什么可以阻止您实现具有等效 64 位哈希函数的基类。但是,您必须编写自己的等效字典。

    【讨论】:

    • 是的,我知道将它们 ^ 组合在一起可以确保考虑所有位 - 很有意义。有趣的是,如果您查看 IntPtr - 用于方法句柄之类的东西 - 它只是截断为 int。如果您在内存的高 32 位中有数据句柄,并且将它们用作键,那就太好了!我同意你关于条件分支的观点——你不能让 32 位/64 位散列对生成它的代码透明。我也同意你关于编写一个新的数据结构来存储更多数据的观点——我想这是你最终不得不接受它的地方。
    • 我可以很容易地想象一个更好的。良好哈希的一个关键特征是完全雪崩,这意味着任何输入位的变化平均会翻转一半的输出位。对两半进行异或运算根本不会产生雪崩。有关详细信息,请参阅here
    猜你喜欢
    • 1970-01-01
    • 2011-09-12
    • 1970-01-01
    • 1970-01-01
    • 2016-01-17
    • 1970-01-01
    • 2011-06-02
    • 2012-12-07
    • 1970-01-01
    相关资源
    最近更新 更多