【问题标题】:Is there a better way to modulate the hash value in this case?在这种情况下,有没有更好的方法来调制哈希值?
【发布时间】:2016-05-27 03:57:53
【问题描述】:

我注意到一个包含奇数个特定字符的字符串,比如“b”,其哈希值为

kM+r

其中kr 是整数,M 是2 的幂。例如,如果 M 是 2 的幂(比如 16),则在调制 M 后,以下所有字符串都会产生相同的值:

"b"          hashCode("b") = 98,            98%16 = 2
"bbb"        hashCode("bbb") = 97314,       97314%16 = 2
"bbbbb"      hashCode("bbbbb") = 293521890, 293521890%16 = 2
...

如果我使用以下公式 (reference) 来调制哈希值,则上述所有字符串都会哈希到同一个桶中,这绝对是我们想要的不是

int bucket_id = (hashCode(str) & 0x7fffffff) % M;

我在这里做错了吗?

【问题讨论】:

    标签: java hash hashmap hashcode hashset


    【解决方案1】:

    通常哈希表实现在分配存储桶之前对对象 hashCode 执行额外的转换。例如,下面是它在 OpenJDK 8 java.util.HashMap 中的实现方式:

    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }
    

    这使得分布更加均匀。 Java-7 使用了更复杂的转换,如下所示:

    int h = key.hashCode();
    h ^= (h >>> 20) ^ (h >>> 12);
    return h ^ (h >>> 7) ^ (h >>> 4);
    

    随着 Java-8 的简化,似乎发现它变得不必要的复杂。

    还确定存储桶仅具有hash(key) & (n-1),其中n 是存储桶的数量。在大多数哈希表实现中,桶的数量是 2 的幂,这样的公式很有效。

    最后,为了防止碰撞(意外或故意),Java 8 实现了新算法,该算法在包含太多元素的桶中创建二叉树(如果键是 Comparable)。这使得在过度拥挤的存储桶中搜索 O(log n) 而不是 O(n)

    【讨论】:

    • 这很有帮助。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2019-03-22
    • 1970-01-01
    • 2022-11-04
    • 2011-11-23
    • 2021-11-15
    • 2017-07-16
    • 2020-01-10
    • 1970-01-01
    相关资源
    最近更新 更多