【问题标题】:Choosing the initial capacity of a HashSet with an expected number of unique values and insertions选择具有预期数量的唯一值和插入的 HashSet 的初始容量
【发布时间】:2009-02-19 11:40:48
【问题描述】:

好的,这是我的情况:

我有一个状态数组,其中可能包含重复项。为了摆脱重复,我可以将它们全部添加到一个集合中。

但是,当我创建 Set 时,它希望定义初始容量和负载因子,但是应该将它们设置为什么?

通过谷歌搜索,我想出了:

String[] allStates = getAllStates();
Set<String> uniqueStates = new HashSet<String>(allStates.length, 0.75);

问题在于 allStates 可以包含 1 到 5000 个状态。所以 Set 的容量将超过 5000,但最多只能包含 50 个。

因此,或者将 Set 的最大大小设置为最大状态数,并将负载因子设置为 1。

我想我的问题确实是:

  • 当您不知道 Set 中有多少项目时,您应该将初始容量设置为多少?
  • 当它可以包含的最大值是 50 时,设置为什么真的很重要吗?
  • 我应该担心吗?

【问题讨论】:

    标签: java set


    【解决方案1】:

    假设您知道不会超过 50 个州(您是指美国的州吗?),

    Set<String> uniqueStates = new HashSet<String>(allStates.length, 0.75);
    

    引用肯定是错误的。为了安全起见,我建议您选择 50 / 0.75 = 67 的初始容量,或者 68。

    我还觉得有必要指出您可能在这方面过度思考。将 arraylist 的大小从 16 调整到 64 两次不会给您带来明显的性能影响,除非这正好在程序中最关键的性能部分。

    所以最好的答案可能是使用:

    new HashSet<String>();
    

    这样一来,一年后你就不会再回来疑惑为什么选择如此奇怪的构造函数参数了。

    【讨论】:

    • +1 表示“一年后回来解谜”。总是发生在未记录的代码上
    • 但我认为在实践中这个值将四舍五入到最接近的二的幂(在本例中为 128)!这对我们的需要来说太过分了
    【解决方案2】:

    在不需要指定这些值的地方使用constructor,然后选择合理的默认值。

    【讨论】:

    • 好吧,明智地避免性能问题,但不要进行微优化。
    【解决方案3】:

    首先,我要说的是,在你的情况下,你肯定是想多了。但是,在某些情况下,人们可能想要正确处理它。所以这就是我的理解:

    1) 您可以在 HashSet 中保存的项目数 = 初始容量 x 加载因子。因此,如果您希望能够容纳 n 个项目,则需要执行 Zarkonnen 所做的操作,然后将 n 除以负载因子。

    2) 在幕后,初始容量四舍五入为per Oracle tutorial 的二次幂。

    3) 如Tom Hawtin - tackline 所述,负载系数应不超过 0.80 以防止过度碰撞。

    如果您只接受默认值(初始容量 = 16,负载系数 = 0.75),那么您的集合最终会增加 3 倍。 (初始最大尺寸 = 12,第一次增加使容量 32 和最大尺寸 24(32 * .75),第二次增加使容量 64 和最大尺寸 48(64 * .75),第三次增加使容量 128 和最大尺寸 96(128 * .75).)

    要使您的最大尺寸接近 50,但要使集合尽可能小,请考虑 64(2 的幂)的初始容量和 0.79 或更高的负载系数。 64 * .79 = 50.56,所以你可以得到所有 50 个州。指定 32 64,否则使用

    所以我的建议是指定初始容量 = 64 和负载因子 = .79。

    【讨论】:

      【解决方案4】:

      安全的选择是选择太小的尺寸。

      因为调整大小可以通过指数增长算法得到改善(请参阅几周前的 stackoverflow 播客),所以变小永远不会花费您那么多。如果你有很多套(你很幸运),那么它们是否过大对性能很重要。

      负载系数是一个棘手的问题。我建议将其保留为默认值。我了解:低于 0.70f 您会使阵列太大,因此速度较慢。高于 0.80f,您将开始遇到许多关键冲突。据推测,探测算法将需要比桶算法更低的负载因子。

      另请注意,“初始容量”的含义与大多数人认为的略有不同。它指的是数组中的条目数。要获得多个元素的确切容量,请除以所需的负载因子(并适当舍入)。

      【讨论】:

        【解决方案5】:

        好好猜一猜。没有硬性规定。如果您知道可能有 10 到 20 个州,我会从这个数字开始 (20)。

        【讨论】:

          【解决方案6】:

          我第二个 Zarkonnen。你的最后一个问题是最重要的。如果这恰好发生在您的应用程序的热点中,则可能值得花精力查看它并尝试进行优化,否则 CPU 周期比烧毁自己的神经元要便宜。

          【讨论】:

            【解决方案7】:

            如果您要对此进行优化 - 并且这样做可能是合适的 - 您的某些决定将取决于您希望数组具有多少重复项。

            • 如果有很多重复项,您将需要一个较小的首字母 容量。迭代时大而稀疏的哈希表很糟糕。

            • 如果预计不会有很多重复项,您将需要 一个初始容量,使得整个阵列可以在没有 调整大小。

            我猜你想要后者,但如果你追求这个,这是值得考虑的事情。

            【讨论】:

              猜你喜欢
              • 2013-08-20
              • 2013-03-04
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-10-23
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多