在这种情况下,是否有更好的方法来调整哈希值?

时间:2016-02-16 03:07:18

标签: java hash hashmap hashcode hashset

我注意到一个包含奇数个特定字符的字符串,比如' 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)来调整哈希值,则所有上述字符串都会哈希到同一个桶中,这绝对是 NOT 我们想要的。

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

我在这里做错了吗?

1 个答案:

答案 0 :(得分:1)

通常,哈希表实现在分配存储桶之前对对象hashCode执行额外的转换。例如,这里是如何在OpenJDK 8 end iterator中实现的:

java.util.HashMap

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

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

似乎发现它不必要地复杂化,因为Java-8简化了它。

此外,确定存储桶只有int h = key.hashCode(); h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); ,其中hash(key) & (n-1)是存储桶的数量。与大多数哈希表实现一样,桶的数量是2的幂,这样的公式很好。

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