【问题标题】:Performance of element-compare in java collectionsjava集合中元素比较的性能
【发布时间】:2015-06-08 14:11:13
【问题描述】:

问题:

给定两个Collection<?>s,检查两者是否包含相同的元素。

  • 假设集合的实际实现是未知的
  • 假设元素的出现顺序不同
  • 假设没有元素在同一个集合中出现两次

解决方案 1:

boolean equals = c1.containsAll(c2) && c2.containsAll(c1);

解决方案 2:

boolean equals = new HashSet<?>(c1).equals(new HashSet<?>(c2));

我会假设 Solution 2Solution 1 更有效 (O(n)) (O(n^ 2)).

我是对的还是我遗漏了什么?

【问题讨论】:

    标签: java performance collections


    【解决方案1】:

    这些的大 O 复杂度是正确的,解决方案 1 涉及为另一个列表中的每个项目(O (n^2))迭代一个列表 (O (n))。解决方案 2 涉及两个 O (n) 副本并迭代一组 (O (n)) 并在另一组上执行 O (1) .contains() 检查。总而言之,这只是O (n)

    但根据您的限制,您可以做得更好(不是渐近更好,只是更好的实现)。

    • 由于我们假设没有重复元素,因此无需进行第二次.containsAll() 检查。只需检查它们的大小是否相同(可能是O (n),但它仍然比复制O (n^2) 检查更好)然后执行.containsAll()

    • 没有必要将c2 转换为Set,因为无论如何它都会被迭代;只需转换c1 并使用.containsAll()

    • 您可以使用instanceof Set 来测试c1c2 是否已经是Set,并使用该对象的.containsAll() 方法;即使另一个对象不是集合,这也会在O (n) 时间内运行,并避免解决方案 2 的复制开销。

    【讨论】:

    • 谢谢!我没有想到尺寸比较。很好的答案。
    • Truth 没有针对这类事情进行了优化,实际上性能可能会差很多。 Truth 是一个测试库,不应在性能关键代码中使用。 (在与真理维护者坐在一起的房间里讲话。)
    • @LouisWasserman 感谢您的洞察力,我已经删除了 Truth 插件。我曾假设 Truth 的流畅设计会使此类优化变得容易,但显然我不应该假设。由于 Truth 不能假设任意集合不包含重复元素,因此它不能安全地将它们同化到集合中。
    • @user902383 我不明白你的意思。 List 不等于 Set,即使它们包含相同的元素。如果你想比较两个Collections的内容,你必须要么使用.containsAll(),要么在使用.equals()之前确保它们是相同的集合类型。
    【解决方案2】:

    正如 dimo414 所说,一般来说,是的。但是你总是可以做得更好(不是渐进地更好,只是更快)。它变得更加复杂:

    if (c1.size() != c2.size()) {
        return false;
    } else if (c1 instanceof Set) {
        return c1.containsAll(c2);
    } else if (c2 instanceof Set) {
        return c2.containsAll(c1);
    } else {
        return new HashSet<>(c1).containsAll(c2);
    }
    

    有些集合的 size 很慢,您可能需要特别处理...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-23
      • 2014-04-24
      • 1970-01-01
      • 2019-07-02
      • 2019-07-08
      • 2018-03-24
      • 1970-01-01
      相关资源
      最近更新 更多