【问题标题】:Combining Java hashcodes into a "master" hashcode将 Java 哈希码组合成“主”哈希码
【发布时间】:2011-02-25 23:11:18
【问题描述】:

我有一个实现了 hashCode() 的向量类。它不是我写的,而是使用 2 个质数乘以 2 个向量分量,然后再对它们进行异或运算。这里是:

    /*class Vector2f*/
...
    public int hashCode()
    {
        return 997 * ((int)x) ^ 991 * ((int)y); //large primes! 
    }

...由于这是来自已建立的 Java 库,我知道它工作得很好。

然后我有一个 Boundary 类,它包含 2 个向量,“start”和“end”(代表一条线的端点)。这两个向量的值就是边界的特征。

    /*class Boundary*/
...
    public int hashCode()
    {
        return 1013 * (start.hashCode()) ^ 1009 * (end.hashCode());
    }

在这里,我尝试为构成此边界的唯一 2 元组向量(开始和结束)创建一个好的 hashCode()。我的问题:这个 hashCode() 实现会起作用吗?

(请注意,我在后面的 hashCode() 实现中使用了 2 个不同的素数;我不知道这是否有必要,但在尝试避免常见因素时,安全总比抱歉要好,我猜——因为我假设这就是为什么素数在散列函数中很受欢迎。)

【问题讨论】:

    标签: java hash


    【解决方案1】:

    这是正常的做法。在我看来这很合理。如果您使用 Eclipse,您应该会发现它可以为您生成 equalshashCode — 只需检查 Source 菜单。它会做同样的事情——枚举您的字段并创建一个检查所有字段的equals 方法,然后选择n 个素数并按照您所做的操作来创建一个hashCode 方法。

    【讨论】:

    • 谢谢 Samir,我不知道 Eclipse 有这个。
    【解决方案2】:

    之所以使用素数(它们不一定是“大”素数)确实是为了避免公因数。

    哈希码由基于哈希的集合类使用,例如HashSetHashMap。如果地图中对象的哈希码尽可能不同,它们的效果最好(如果这些对象的哈希码相同,它们必须做更多的工作来区分对象)。

    将用于生成组合哈希码的部分的哈希码与素数相乘可确保这些部分没有公因数,因此冲突的可能性较小(关于不同部分的哈希码相互重叠)。

    【讨论】:

    • 所以我做对了,然后建议我在 Boundary.hashCode() 中使用 不同的素数对底层 Vector2f.hashCode() 实现?或者如果我同时使用 997 和 991 会一样吗? AFAIK,由于 XOR 是旋转位,因此 XOR 产生的整数不一定是素数(或非素数),这意味着我是否使用同一对素数无关紧要?跨度>
    • 我不完全确定;如果使用 + 而不是 XOR,那么很清楚 - 你应该使用不同的素数。所以我会这样做只是为了安全。请注意,XOR 几乎就像加数字一样,但没有携带位(即1 ^ 1 = 0 而不是10,向前携带位)。我还没想过这究竟会如何影响结果。
    • @Nick Wiggill 我相信重要的是被乘以的素数不是哈希表底层数组大小的一个因素。如果乘以 17,则数组的大小为 34,那么所有对象最终都将位于位置 0 或 17(导致大量碰撞)。
    • 使用 ^ 代替 + 存在一个主要危险。在一系列 ^ 中重复相同的元素将相互抵消。 (N ^ Y ^ N = Y) 这是因为它在每一步都被相乘。
    猜你喜欢
    • 2012-09-16
    • 1970-01-01
    • 2019-05-03
    • 2016-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-19
    • 2014-12-31
    相关资源
    最近更新 更多