【问题标题】:Which one is faster? List.contains() or Map.containsKey()哪个更快? List.contains() 或 Map.containsKey()
【发布时间】:2012-07-21 17:44:16
【问题描述】:

我正在编写一个算法,我在其中查找成对的值,当它们相加时会产生我正在寻找的另一个值。

我发现使用Map 可以加快我的算法从 O(n²) 的速度。后来我意识到我并没有真正使用 Map 中包含的值,所以 List 就足够了。

我在 Google 上进行了强力搜索,但在我的问题标题中没有找到有关这些方法的渐近运行时间的任何信息。

你能指出我应该在哪里寻找这些信息吗?

【问题讨论】:

  • 更公平的比较是Set.contians() vs Map.containsKey(),这基本上是相等的 - 对于每种类型的 Map 都有一个对应的 Set 类型在其 impl 中使用
  • 我知道我知道,但我认为对 JCF 代码执行渐近分析需要几个小时的项目。
  • 听起来您想将值放入列表中,并从两端不规则地迭代以匹配总和。仍然是 O(n)。对于更复杂的对,布隆过滤器可能是合适的。

标签: java list collections map


【解决方案1】:

我后来意识到我并没有真正使用 Map 中包含的值,所以 List 就足够了。

Map 不仅仅是键值对的列表,它是键到值的唯一映射。因此,当您从 Map 更改为 List 时,您将允许以前不允许的重复项。另一方面,Set 正是没有值的Map。所以考虑使用HashSet

至于搜索的复杂性:

list.contains 是 O(n),hashSet.contains 是 O(1),treeSet.contains 是 O(log n)。

有关现在HashMap 工作的一般信息,请在谷歌搜索“哈希表”。对于TreeMap,谷歌搜索“二叉树”或类似名称。维基百科在这些主题上有很好的条目。

不过,请小心避免使用 Hashtable 类。它是现代图书馆中的一件考古文物。对于您的情况,HashSet 可能是最好的选择。

【讨论】:

    【解决方案2】:

    Map.containsKey() 考虑到您正在使用 HashMap,因为在 HashMap 中的搜索是在 O(1) 中完成的。

    List.contains() 通常应该采用顺序搜索或二分搜索,因此复杂度至少为 O(log n)

    【讨论】:

      【解决方案3】:

      MapList是接口,所以没有关于它们的实现和性能的信息。但是,如果您使用最新的实现(LinkedListArrayList 用于ListHashMap 用于Map),在最坏的情况下,contains() 方法必须遍历整个列表,并且将您的元素与每个条目进行比较。这是一个 O(n) 操作。

      如果您使用HashMap,则实现完全不同:HashMap 包含一个数组,其中的条目比其中的元素多(实际上,数组大小在 4n/3 到 3n/2 之间)地图中的 n 个元素)。它计算密钥的哈希值,它是一个 int,并将其包装在 0 和您的数组大小之间(假设这个数字是 i)。然后它会将元素放在数组的索引i(或i+1i+2……如果之前的索引已经被占用)。因此,当您使用containsKey 检查密钥是否存在时,它将重新计算哈希值和i 值,并检查ii+1... 索引,直到找到一个空数组单元格。从理论上讲,你可以有一个 O(n) 最坏的情况,如果数组几乎满了,所有的键都有几乎相同的i 值,但是有一个好的散列函数,你有恒定时间contains 和 @ 987654341@ 功能。 (但是,如果您不需要调整数组的大小,添加元素会很快,这真的很慢 - 我认为您需要重新计算每个键的索引)。

      因此,如果您需要检查集合中的键外观,并且不需要保持顺序(有一个SortedHashMap,但我不知道它的性能),那么地图确实更快,但是这将占用更多内存。

      另外,如果您不需要键值对,您可以使用HashSet(内部与HashMap 相同)。

      【讨论】:

      • 那是因为我想知道所有实现的速度。
      【解决方案4】:

      HashSet 似乎更快:

      • 哈希映射:267
      • 数组列表:2183
      • 哈希集:57

      还要注意 .contains() 通常不需要在 HashMap 和 HashSet 上调用,但我将其保留在代码中以更准确地回答您的问题:

          long t = System.currentTimeMillis();
          HashMap<String, Boolean> map = new HashMap<>();
          for (int i = 0; i < 10000; i++) {
              String s = (Math.random() * 100) + "";
              if (!map.containsKey(s)) {
                  map.put(s, true);
              }
          }
          System.out.println("HashMap: " + (System.currentTimeMillis() - t));
      
          t = System.currentTimeMillis();
          ArrayList<String> list = new ArrayList<>();
          for (int i = 0; i < 10000; i++) {
              String s = (Math.random() * 100) + "";
              if (!list.contains(s)) {
                  list.add(s);
              }
          }
          System.out.println("ArrayList: " + (System.currentTimeMillis() - t));
      
          t = System.currentTimeMillis();
          HashSet<String> set = new HashSet<>();
          for (int i = 0; i < 10000; i++) {
              String s = (Math.random() * 100) + "";
              if (!set.contains(s)) {
                  set.add(s);
              }
          }
          System.out.println("HashSet: " + (System.currentTimeMillis() - t));
      

      【讨论】:

        猜你喜欢
        • 2010-11-10
        • 2012-10-03
        • 2011-02-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-05
        • 1970-01-01
        相关资源
        最近更新 更多