【问题标题】:Why index of hashcode is calculated in HashMap为什么在HashMap中计算hashcode的索引
【发布时间】:2017-05-16 23:30:46
【问题描述】:

我正在检查HashMap 的实现,在它的put 中我看到计算哈希后,计算哈希的索引,就像这样int i = indexFor(hash, table.length);,它被用作底层映射的索引。

/**
 * Returns index for hash code h.
 */
static int indexFor(int h, int length) {
    return h & (length-1);
}

我搜索没有找到任何解释我的问题,即为什么要再次计算哈希索引,该索引用作底层数据结构的最终索引。与使用哈希作为索引相比,它有什么优势。

我知道它只是按位与,但我想知道为什么会这样。

【问题讨论】:

  • 因为你需要哈希值 mod 桶的数量! [0, n-1]
  • 所以这就像模数?我的意思是h % (length -1)
  • @pjj 是的,如果 length 是二的幂。例如,如果length 为 8,则低 3 位提供模数 (8 - 1 = 7 = 0111)。

标签: java hash hashmap


【解决方案1】:

对象的哈希码可以是介于 -2^31 和 2^31-1 之间的任何 int 值。哈希表使用的底层数组不会具有相同的范围(没有负数,对于一个,并且可能没有那么大),因此必须有一些操作将哈希码从其原始范围转换为介于 0 和数组的长度。

因为HashMap 总是使用大小为 2 的幂的数组(例如 16、32、64 等),所以使用 & 是一种将哈希码映射到索引的有效方法,因为它只是去除了其他位。如果不将数组大小限制为 2 的幂,其他哈希表实现可能会使用模数来达到类似的效果。

另见https://en.wikipedia.org/wiki/Hash_table#Collision_resolution

【讨论】:

  • 感谢您的回答,但int hash = hash(key.hashCode()); 可能会返回一些大于数组长度的值,还是它总是返回小于数组长度的值?从您的回答中,我了解到这会更小/
  • @pjj 内部的hash() 方法有一个完全不同的目的,它试图最小化某些类型的哈希值的哈希冲突。出于您的问题的目的,请忽略该电话。 --- 对于你的问题,hashCode() 可以返回int 范围内的整数,但哈希表只有 X 个桶。要将哈希码“映射”到存储桶,您需要计算 hashCode() % X 以生成有效的存储桶编号(使用 unsigned 整数数学)。由于 X 始终是 2 的幂,所以可以用速度更快的按位运算 & 替换较慢的 % 模运算符。
  • @pjj - 我在描述哈希表的一般工作方式,以及HashMap 在实践中的工作方式。有很多额外的实现细节(例如HashMap.hash())不如一般原则重要。如果您对HashMap.hash() 特别感兴趣,源代码中的 cmets 会解释其用途。正如 Andreas 所说,这与您最初的问题无关。
猜你喜欢
  • 2017-12-12
  • 2015-03-07
  • 2012-09-17
  • 2020-12-12
  • 2021-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-20
相关资源
最近更新 更多