为什么返回(h = key.hashCode())^(h>>> 16)而不是key.hashcode?

时间:2017-07-16 05:52:36

标签: java hashmap

我没有看到这种方法可以避免碰撞。我认为如果key.hashcode大于table.length,则会发生碰撞。

更新: 实际上我指的是JDK 1.8中的HashMap#hash,并且对于向下传播较高位的好处有点困惑。 现在,我想在link的帮助下我很清楚,好处是:

  • 我们不需要进行%计算,但使用更快的方式 - 位移。

对于碰撞,如果密钥的数量大于表的长度,则无论使用何种哈希方法都会发生冲突。

2 个答案:

答案 0 :(得分:2)

让我们说你天真地使用

索引到一个哈希表
int index = hashcode % table.length;

在某些常见用例中,这可能会导致许多冲突。例如,假设table.length是2的小幂(如32或64)。在这种情况下,只有哈希码的低阶位确定索引。如果您的对象的哈希码仅在高位中有所不同,则会导致大量冲突。位移允许哈希码的高位也影响计算的索引。

答案 1 :(得分:2)

原因在于评论:

  

计算key.hashCode()并将散列(XOR)更高的散列位降低。因为该表使用2次幂掩蔽,所以仅在当前掩码之上的位中变化的散列组将始终发生冲突。 (在已知的例子中有一组Float键,在小表中保存连续的整数。)

用简单的话来说,Key#hashcode(我们关心的最后一位)对于实际上不同的密钥是相同的。这会产生冲突,因为这些条目最终将在同一个桶中。

条目的位置取决于现有存储桶的数量或最后的n位,如您所见:

int index = (n - 1) & hash

如果hashmap不会再次重新哈希 - 这意味着那些最后一位不同的条目最终将在同一个桶中,搜索时间= =更慢。

使用XOR的原因 - 因为它具有{/ 1}}和1的50/​​50%分布(而不是0|有75/25或25/75)。

使用&操作代替&,不仅仅用于速度,而是因为哈希码是%并且可以是负数。负数上的模数将为负数 - 意味着负数桶...因此使用int将生成正指数。