【问题标题】:How to compare the complexity of two methods in Java?如何比较Java中两种方法的复杂度?
【发布时间】:2015-09-06 13:46:29
【问题描述】:

如何比较这两种方法的O 复杂度?

这里是第一种方法:

protected static List<Integer> removeDuplicates1(List<Integer> source) {
    List<Integer> tmp = new ArrayList<Integer>();
    for (Integer element : source) {
        if (!tmp.contains(element)) {
            tmp.add(element);
        }
    }

    //Collections.sort(tmp);
    return tmp;
}

第二个:

protected static List<Integer> removeDuplicates2(List<Integer> source)  {
    return new ArrayList<Integer>(new HashSet<Integer>(source));
}

UPD

我不知道如何计算这两种方法的 O 复杂度。

UPD2

好的,第一种方法的时间复杂度是O(n^2),第二种是O(n)。那么内存使用情况呢?谁更贪婪,为什么?

【问题讨论】:

  • 查看源代码,如果您不能提供大量列表并测量时间(至少对于时间复杂度而言)。有一些工具可以监控堆/堆栈使用情况,其中最简单的工具之一是在 jdk 中构建“ jconsole" 位于 bin 目录中
  • 你知道如何计算每一个的O复杂度吗?如果你这样做了,那么比较它们应该很容易。如果您不这样做,请编辑您的问题以反映这一点,因为措辞似乎建议您这样做。我不确定问题到底是什么。
  • @Palcente 我一直认为算法复杂度是一个与某些理论有关的东西,与实践无关。
  • @yshavit 我不知道该怎么做。
  • 哪一个?两个都?您阅读过哪些计算大 O 的资源,以及在此处应用这些资源有哪些不明白的地方?到目前为止,这个问题非常广泛,基本上是“我如何计算大 O”——对于 SO 的格式来说太宽泛了。

标签: java time-complexity space-complexity


【解决方案1】:

第二个更好 O(n) 复杂度(O(n^2) 第一个)。

首先,您遍历循环中的列表 (n),然后为每个操作运行 contains(),然后依次遍历 tmp 列表以查找元素是否存在(还有一个 n)。

对于第二种方法,添加Set 的操作是恒定的,所以实际上只有一个n

【讨论】:

  • 所有这些都是从查看 ArrayList 和 HashSet 的实现中学到的(或者相信 Javadoc 所说的)。可以向 ArrayList 添加一些内容,这将使包含 O(1)。
  • @laune no. contains() for list 检查所有元素。实际上遍历列表。当然可以添加一些东西……但那不是 ArrayList
  • 我当然知道 java.util.ArrayList.contains 是做什么的。请阅读我写的内容:我说这是可能的,并且您需要查看实现才能确定。 OP 似乎怀疑查看实施的必要性。向 ArrayList 添加一些内容不会使其失去合同,即其实现的接口。
  • @laune 参见例如stackoverflow.com/questions/5771740/… 如果您修改列表以具有恒定时间 contains() 这将意味着您应该以某种方式合并列表并设置哪个反过来将我们引向方法 2。
  • 嘿,这就是我想说的:-) 你需要看看实际的实现。我认为这是 Palcente 的建议。
【解决方案2】:

第二种方法效果更好,因为它的复杂性是O(n),而第一种方法在O(n^2) 中运行。

在大 O 表示法的情况下,第二个解决方案的复杂性是 O(n),因为它只在 List 中循环一次。在第一种情况下,它首先 for 循环运行一次,但内部包含 mehtod 再次在临时列表上运行。所以这种情况下的复杂度是O(n^2)。

【讨论】:

    【解决方案3】:

    不要尝试在 Java 中执行此操作,只需尝试在伪代码中执行此操作。

    在第一个问题中,您有两个整数列表;两个数字列表。如果没有给出任何其他规则,我们可以假设两个列表大约有 n 项长。

    您正在遍历其中一个列表,并为其中的每个数字做一些事情。如果有n个数字,那就是n个步骤。对于这 n 个步骤中的每一个,您都在说“另一个列表有这个数字吗?”

    要检查列表中是否有数字,最坏的情况是它没有,这意味着您必须检查列表中的每个项目才能找到。如果第二个列表与第一个列表一样大,那也是 n 步。

    把它们放在一起: 遍历包含 n 个项目的列表,并对每个项目做 n 件事。

    让我知道你的想法,然后我会编辑这个答案。

    对于您的第二个代码 sn-p,将其拆分。

    首先要使用输入中的所有项目创建一个 HashSet。将一项插入 HashSet 需要多长时间?如果插入 n 项,则将单个插入的时间乘以 n。

    发生的第二件事是调用了新的 ArrayList。检查 API 以确定它在做什么: http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html#ArrayList(java.util.Collection)

    它使用 HashSet 集合中的所有项目创建一个 ArrayList。插入数组列表需要多长时间?将其乘以项目数 (n) 即可得到答案。

    由于这些是作为单独的步骤发生的,因此它们是单独的事情。 big-O 复杂度较高的那个是主要的,你可以忽略另一个。如果它们都具有相同的大 O 复杂性,那就是答案;您可以忽略一个,因为 O(2n) 与 O(n) 的复杂度相同;常量(如 2x)被丢弃。

    【讨论】:

    • 如果您要投反对票,请告诉我原因以便我改进?
    • 您在编辑过程中删除了一些错误,所以我要收回 -1。
    猜你喜欢
    • 2014-01-14
    • 1970-01-01
    • 2015-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-14
    • 2022-01-13
    相关资源
    最近更新 更多