【问题标题】:What is the time complexity of java.util.HashMap class' keySet() method?java.util.HashMap 类的 keySet() 方法的时间复杂度是多少?
【发布时间】:2010-12-23 11:24:58
【问题描述】:

我正在尝试实现平面扫描算法,为此我需要知道java.util.HashMap class' keySet() 方法的时间复杂度。我怀疑它是 O(n log n)。我说的对吗?

澄清点:我说的是keySet()方法的时间复杂度;遍历返回的 Set 显然需要 O(n) 时间。

【问题讨论】:

  • 我不认为遍历集合需要'明显' O(n) 时间。该集合可能不会实际生成。它可能只是一个可用于迭代的对象。而且,这里的 n 是什么?物品还是水桶?
  • 这里 n 是哈希图中的条目数。如果集合有 n 个元素,要迭代 n 个元素的集合,时间复杂度将为 O(n)。

标签: java algorithm hashmap complexity-theory


【解决方案1】:

获取密钥集是O(1),而且很便宜。这是因为HashMap.keyset() 返回与HashMap 关联的实际KeySet 对象。

返回的Set 不是密钥的副本,而是实际HashMap 状态的包装器。实际上,如果您更新集合,您实际上可以更改HashMap 的状态;例如在集合上调用clear() 将清除HashMap


... 遍历返回的Set 显然需要O(n) 时间。

其实这并不是总是为真:

  • HashMap 是使用 new HashMap<>() 创建的。最坏的情况是让所有N 密钥都位于同一个哈希链中。但是,如果地图自然增长,哈希数组中仍然会有N 条目和O(N) 槽。因此迭代条目集将涉及O(N) 操作。

  • 如果HashMap 是用new HashMap<>(capacity) 和一个非常糟糕(太大)的capacity 估计值创建的,那么它是错误的。然后它将采用O(Cap) + O(N) 操作来迭代条目集。如果我们把Cap当作一个变量,那就是O(max(Cap, N)),它可能比O(N)更糟糕。

虽然有一个转义子句。由于capacity 是当前HashMap API 中的int,因此Cap 的上限为231。因此对于CapN真正 大值,复杂度为O(N)

另一方面,N 受到可用内存量的限制,实际上您需要一个大约 238 个字节 (256GBytes) 的堆以供 N 超过最大可能的Cap 值。对于这样大小的地图,您最好使用针对大型地图调整的哈希表实现。或者没有使用过大的容量估计!

【讨论】:

  • (注意:本答案的第二部分原本是一个单独的答案。)
【解决方案2】:

为了解决“迭代返回的 Set 显然需要 O(n) 时间”的评论,这实际上是不正确的,根据 HashMapdoc comments

对集合视图的迭代需要的时间与 HashMap 实例的“容量”(桶的数量)加上其大小(键值映射的数量)成正比。因此,如果迭代性能很重要,那么不要将初始容量设置得太高(或负载因子太低)。

换句话说,遍历返回的Set 将采用O(n + c),其中n 是地图的大小,c 是其容量,而不是O(n)。如果选择了大小不合适的初始容量或负载因子,则c 的值可能会在迭代时间方面超过地图的实际大小。

【讨论】:

  • 重复答案。说的是我 9 个月前写的。
  • @StephenC 我会相信你的话,因为看起来你已经删除了那个答案并将其合并到你的另一个答案中,而且我没有足够的声誉来查看已删除答案。我一定错过了你对这一点的回答。
【解决方案3】:

这应该在 O(n) 时间内是可行的...哈希映射通常实现为一个大桶数组,桶的大小(通常)与哈希映射的大小成正比。为了检索密钥集,必须迭代桶,并且对于每个集合项,必须检索密钥(通过中间集合或直接访问桶的迭代器)...

**编辑:正如其他人指出的那样,实际的 keyset() 方法将在 O(1) 时间内运行,但是,迭代 keyset 或将其转移到专用集合将是 O(n) 操作。不太确定你在找哪一个**

【讨论】:

  • O(n) 并不完全准确,根据my answer(迭代的时间复杂度取决于地图大小及其容量,尽管容量部分不应该改变迭代时间复杂度,除非地图的数据配置不当)。
  • @M.Justin - 根据我的回答......从 9 个月前开始。
【解决方案4】:

Java 集合有很多空间,因此不需要太多时间。我相信这种方法是 O(1)。收藏品就在那里。

【讨论】:

    【解决方案5】:

    肯定是 O(1)。它所做的只是在 HashMap 上返回一个包装对象。

    如果你说的是遍历键集,那么这是 O(n),因为每个 next() 调用都是 O(1),并且需要执行 n 次。

    【讨论】:

    • O(n) 并不完全准确,根据my answer(迭代的时间复杂度取决于地图大小及其容量,尽管容量部分不应该改变迭代时间复杂度,除非地图的数据配置不当)。
    猜你喜欢
    • 2018-01-18
    • 2011-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-26
    • 2019-05-14
    相关资源
    最近更新 更多