【问题标题】:number of hash buckets哈希桶数
【发布时间】:2012-04-30 06:31:47
【问题描述】:

HashMap 文档中提到:

  • 初始容量就是创建哈希表时的容量
  • 容量是哈希表中的桶数。

现在假设我们的初始容量为 16(默认),如果我们继续向 100 个添加元素,则 hashmap 的容量为 100 * loadfactor。

请问哈希桶的数量是100还是16?

编辑:
从我读到的解决方案中:存储桶不仅仅是添加的元素。 以此为观点:所以如果我们添加字符串作为键,我们将得到一个元素/桶,从而导致大量的空间消耗/复杂性,我的理解对吗?

【问题讨论】:

    标签: java hashmap


    【解决方案1】:

    既不是 100 也不是 16 桶。很可能会有 256 个存储桶,但文档并不能保证这一点。

    来自updated documentation link

    负载因子是哈希表在其容量自动增加之前允许达到的程度的度量。当哈希表中的条目数超过负载因子和当前容量的乘积时,对哈希表进行重新哈希(即重建内部数据结构),使哈希表大约有两倍 桶数。

    (强调我的)

    所以,如果我们忽略上面的“大约”这个词,我们会确定只要哈希表达到 75% 满(或您在构造函数中指定的任何负载因子),哈希桶的数量就会翻倍。这意味着每当您插入第 12、24、48 和 96 个元素时,桶的数量就会翻倍,总共剩下 256 个桶。

    但是,正如我在文档 sn-p 中强调的那样,这个数字是之前大小的大约两倍,因此它可能不完全是 256。事实上,如果倒数第二个加倍换成稍微大一点的增加,最后的加倍可能永远不会发生,所以最终的哈希表可能小到 134 个桶,也可能大于 256 个元素。

    注意我得到了 134 数字,因为它是 N 的最小整数,使得 0.75 * N > 100

    【讨论】:

    • +1 用于引用文档。附带说明:从 Java 7 源代码来看,容量看起来恰好翻了一番(或者当putAll() 与大地图一起使用时,容量增加了四倍或更多)——事实上,在桶表:Length MUST Always be a power of two. - AFAIK 没有 2 的幂的近似值 :)
    • @Adam 我的猜测是正确的:根据上面的讨论,hashbuckets 将保持超过 hashmap 中键的数量,因此如果将 diff 整数作为键,发生冲突的机会应该为零?
    • @Naroji 仅仅因为哈希表中的桶比键多,not 就不可能发生冲突,即使所有键都是唯一的。在某些问题中,如果您真的为您的域量身定制散列函数,并且允许您的散列函数考虑散列表大小,则可以设计这样的散列函数(这称为完美散列),但事实并非如此在爪哇。在大小为 N 的哈希表中,如果给定两个哈希码对于某个整数 k 相差 kN 的键,大多数实现都会产生冲突。
    • @Adam 举个例子:哈希表大小:16(哈希码从 1 到 16),当我添加第 12/13 个元素时,桶大小增加到 32(差异哈希码)。现在当我添加第 24/26 个元素时,它应该进入第 24/26 个桶(而不是第 12/13 个桶)。这没有意义吗
    • @Naroji 我不确定我是否理解你的问题。我的观点是JavahashCode()方法不依赖于哈希表的大小,不仅两个不同的对象可以具有相同的哈希码,而且可以将两个具有不同哈希码的不同对象放入同一个桶中因为哈希表中的桶数远小于来自hashCode()的可能返回值的数量。
    【解决方案2】:

    查看HashMap的源码我们看到如下:

    threshold = capacity * loadfactor
    size = number of elements in the map
    
    if( size >= threshold ) {
      double capacity
    }
    

    因此,如果初始容量为 16,并且您的负载因子为 0.75(默认值),则初始阈值将为 12。如果添加第 12 个元素,容量将上升到 32,阈值为 24。下一步将是容量 64 和阈值 48 等等。

    所以对于 100 个元素,你应该有 256 个容量和 192 个阈值。

    请注意,这仅适用于标准值。如果您知道地图将包含的大致元素数量,您应该使用足够高的初始容量创建它,以防止在容量增加时复制。

    更新

    关于容量的一个词:它始终是 2 的幂,即使您定义了不同的初始容量。然后哈希图会将容量设置为大于或等于提供的初始容量的 2 的最小幂。

    【讨论】:

    • @Thomas 谢谢你的好回答......一个疑问......容量是否意味着“没有哈希桶”?
    • @jain007 我也会引用文档:...the "capacity" of the HashMap instance (the number of buckets)... - 所以,是的,容量就是桶的数量。
    • @Thomas 那么存在 12 个元素是什么意思?这是否意味着 Hashmap 有 12 个键或 12 个桶至少映射了一个元素?
    • @piechuckerr 我不确定是什么让你感到困惑,但我指的是地图中的条目,即映射到键的值(因此你可以说元素 = 某种意义上的键)。
    【解决方案3】:

    doc

    When the number of entries in the hash table exceeds the product of the 
    load factor and the current capacity, the capacity is roughly doubled by 
    calling the rehash method.
    
    threshold=product of the  load factor and the current capacity
    

    让我们试试.. hashmap 的初始大小是 16
    并且默认负载因子是0.75所以第一个阈值是12所以添加12个元素下一个容量将是.. (16*2) =32
    第二个阈值是 24,所以在添加第 24 个元素后,下一个容量将是 (32*2)=64

    等等……

    【讨论】:

      【解决方案4】:

      来自您的链接:

      当哈希表中的条目数超过负载因子与当前容量的乘积时,通过调用rehash方法,容量大致翻倍。

      这意味着如果我们的初始容量为 16,当超过时,容量将增加 32,下一次增加 64,依此类推。

      在您的情况下,您要添加 100 个。因此,当您到达第 16 个数字时,大小将增加 32,因此现在总大小为 48。再次继续添加直到第 48 个数字,大小将增加 64。因此,在您的情况下,存储桶的总大小为 112。

      【讨论】:

        【解决方案5】:

        您将有至少每个实际项目一个桶。如果您添加的项目超过 16 个,则必须调整表格的大小并重新散列。

        现在假设我们的初始容量为 16(默认),如果我们保持 将元素添加到100个,hashmap的容量为100 * 负载系数。

        其实是这样写的:

        如果初始容量大于最大条目数 除以负载因子,不会发生重新哈希操作。

        即,如果最多有 100 个项目并且容量为 100/0.75 = 133,则不应该发生重新散列。请注意,这意味着即使表未满,当接近满时也可能需要重新散列。因此,如果您期望

        【讨论】:

          猜你喜欢
          • 2011-08-22
          • 1970-01-01
          • 2010-09-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多