【问题标题】:Capacity and indexFor in Java HashmapJava Hashmap 中的容量和 indexFor
【发布时间】:2018-01-10 08:37:39
【问题描述】:

通过JavaHashMap的源码,我们可以看到key的第一个bucket是通过如下方法确定的:

 static int indexFor(int h, int length) { //h = hash of key 
     return h & (length-1);               //length = capacity of array at 
 }                                        //         current time

根据我的理解,如果初始大小是 16 (length-1 = 15 = 1111) 并且如果生成的密钥 k1 的哈希是 108378 (1 10100111 01011010),那么 indexFor() 方法将返回 10 (1010)。

现在,假设经过一些添加后容量已更改为32。现在,如果我想搜索密钥 k1(哈希为 108378),它将再次使用相同的 indexFor() 方法检查存储桶。现在h & (length-1) 代码 sn-p 将返回26。 (108378 & 31)。

我的问题是,如果表被调整大小,这个 get 方法将如何找到正确的存储桶?

【问题讨论】:

  • 调整表大小时,桶会被重组。
  • 调整表格大小时,所有键的哈希值都会重新计算并移动。

标签: java hash hashmap hashtable


【解决方案1】:

您看到的length 不是map.size() 报告的值。它是一个内部长度,表示哈希表的大小。这个长度可以在密集的哈希图中小于size(),也可以在稀疏的哈希图中大于size()。它越小,就会发现越多的键对h & (length-1) 具有相同的评估,这意味着更多的键将被分组到桶中。

在某些(希望尽可能少)时间点,地图认为 length 太小,导致太多冲突(每个桶中的键太多),因此它重新组织映射,将哈希表重新分配到更大的大小,重新计算所有哈希值,并在桶中重新分配键,以便 h & (length-1) 对于所有哈希值仍然正确。

【讨论】:

    【解决方案2】:

    当达到负载因子的最大阈值时,会发生称为 Rehashing 的过程,并将所有元素移动到一个新表中。

    当哈希表中的条目数超过 负载因子和当前容量,哈希表为 rehashed(即重建内部数据结构)所以 哈希表的桶数大约是两倍。

    地图中的预期条目数及其负载系数 在设置其初始容量时应考虑到,所以 以尽量减少重新哈希操作的次数。

    【讨论】:

    • 谢谢。除了您的回答,我还有另一个问题。如果已经应用了链接,那么在重新散列期间,是否还会为链接的节点重新计算存储桶#?还是只是链接节点的起始节点?
    • 对所有值进行重新计算,因为之前持有相同桶位置的节点 - 现在可以分布在不同的桶位置。
    【解决方案3】:

    如果表格被调整大小,那么长度参数将会改变,indexFor 方法将返回一个不同的值。当表被调整大小时,当前在表中的值必须被移动到新表中,因此将为每个值计算一个新的索引。

    【讨论】:

    • 好的...我明白了。谢谢。但令我惊讶的是调整大小时的时间和空间复杂性。我相信在操作过程中它没有遵循 O(n) 复杂性。
    • @AnirbanB 在重新哈希期间,时间复杂度为 O(n),因为旧哈希表中的所有元素都必须计算新哈希码,然后计算索引,然后放入新表。它不如添加单个元素那么有效,但仍然是 O(n)。
    • 是的...刚刚意识到它实际上是 O(n)。但平均情况是 O(1)。但是空间复杂度远大于 O(n)。
    猜你喜欢
    • 1970-01-01
    • 2017-01-25
    • 1970-01-01
    • 2013-03-16
    • 2019-03-12
    • 2018-11-03
    • 2018-01-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多