【问题标题】:Do "if" statements affect in the time complexity analysis?“if”语句会影响时间复杂度分析吗?
【发布时间】:2012-09-01 21:19:21
【问题描述】:

根据我的分析,这个算法的运行时间应该是N2,因为每个循环都会遍历所有元素。我不确定if 语句的存在是否会改变时间复杂度?

for(int i=0; i<N; i++){
    for(int j=1; j<N; j++){

        System.out.println("Yayyyy");
        if(i<=j){
            System.out.println("Yayyy not");
        }
    }
}

【问题讨论】:

  • if 只是一个声明;它只会影响使用朗道符号时丢失的系数。无论如何,O 是渐近增长的上限。
  • 不,主要操作仍然是打印。
  • 你怎么知道这是主导操作?
  • 运行时间是什么意思?你是这个意思吗?还是你的意思是Big O
  • @DarthVader 我的意思是每次循环迭代都会发生打印。

标签: java algorithm complexity-theory


【解决方案1】:
  • Tp:将常量文本打印到标准输出所需的时间。
  • Ti:内部循环内所有其他操作(谓词评估等)所花费的时间。
  • :除执行内循环(初始化计数器等)外,外循环内所有操作所需的时间。
  • Tc:设置流程和所有其他簿记所需的时间

总运行时间将为Tc + N x (To + NxTi + N/2xTp)

这等于 Tc + NxTo + (Nx(N/2)) x (2Ti + Tp)K x (N^2) 为界对于 K > Ti + Tp/2 的值,因为 N 趋于无穷大。这个边界使得时间复杂度仍然O(N^2)

不,if 语句不会改变本例中的时间复杂度。

【讨论】:

  • 考虑一下,上例中有 100 个 if 语句,(没有 else 块)在某些时候会不会影响程序的整体时间复杂度?如果是的话,那可能是什么?我知道设置这么多条件会是不好的编程习惯或者可能很愚蠢,但我只是要求更好地理解。
  • @Akshit:时间复杂度是运行时间相对于输入大小如何变化的度量,它不是运行时间本身的绝对度量。在这个循环中添加更多的条件语句肯定会增加运行时间,但是运行时间相对于输入大小 N 增加的速率仍然由 O(N^2) 控制。
【解决方案2】:

没有。考虑到时间复杂度渐近地描述时间 - 我们将较低的时间复杂度吸收到较高的时间复杂度中。

O(n²) 表示k × n² + c,假设c 太低以至于我们不关心它。

这些是恒定的影响,整个事物的一定数量的开销 (c) 以及无论我们的复杂性如何,一定数量的成本。一个 算法将击败另一个 算法,如果它有一个较低的k,或者如果它们相等,一个较低的c。此外,对于足够低的 n 值,O(n²) 与 O(1) 相同(我们通常不会关心,但每个的 k 可能会有很大不同,而且如果我们每做一次 m 次,那么虽然 O(n²m) 优于 O(m),但如果 n 较低,则不是真正比较的对象)..

无论如何,这是故意的过度简化,因为kc 可能并不真正是恒定的,就像恒定一样好。因此,如果某个东西真的是O(n² + log(n)),我们就称它为O(n²),因为当我们有一个 需要担心时,谁会关心那个小log(n)

所以。看着你的情况。我们做外循环,n 次。对于其中的每一个,我们执行内部循环n-1 次。对于每个内部循环,我们进行第一次打印(任何成本差异都与n 无关,因此基本上是恒定的)和测试。测试成功的时间大约有一半,导致第二次打印的成本经常如此。

所以总成本是:

cost of setting up everything +
n × cost of looping + 
(n - 1) × cost of loop +
(n × (n - 1)) × cost of print +
(n × (n - 1)) × cost of test +
(n × (n - 1)) / 2 × cost of print.

为上面的常量赋值,我们得到:

k +
n × a +
(n - 1) × b +
(n × (n - 1)) × c +
(n × (n - 1)) × d +
(n × (n - 1)) / 2 × e.

=

k +
n × a +
(n - 1) × b +
(n × (n - 1)) × (c + d + (e / 2))

现在,由于c + d + e / 2 本身是常数,所以可以变成:

n × a + (n - 1) × b + (n × (n - 1)) × c + k

或重新排序,按最高顺序在前:

(n × (n - 1)) × c + (n - 1) × b + n × a + k

如果 n 高到足以让我们该死,那么 n 在比例上如此接近 n - 1,以至于我们不妨认为它们是相同的(时间复杂度的另一个方面是渐近地描述事物,即当 n 接近 ∞因此 n² 和 (n × (n - 1)) 之间的差异接近 0)。因此:

n² × c + n × b + n × a = n² × c + n × (b + a) + k

同样,b + a 本身就是常数,所以它等价于:

n² × k + n × c + a

现在我们做了前面提到的吸收较低时间的订单,谁在乎n × c,没关系吗?如果 n 高到足以让我们完全关心,那么这就是。相比之下,我们不妨将总体开销的差异视为噪声,并将其视为:

n² × k + c

或者换句话说,如:

O(n²)

所以是的,你一开始就很努力,if 语句不会影响复杂性。

考虑到这一点,我们可以注意到时间复杂度可能会隐藏我们真正关心的内容。例如,如果我们有一个 O(n²) 算法,如果这种分析发现时间成本为n² × k + n × c,k 为 200µs,c 为 15s,那么直到 n 大于 750000 它实际上是每 n 位成本,而不是每 n² 位。在较低的 n 时,它更接近我们对 O(n) 的期望,而不是 O(n²)。

时间复杂度有用的原因是,如此大的差异是罕见的,而且我们关心时间,因此关心时间复杂度,当 n 变高时(你可以隐藏一些可怕的 O(n !)代码中的怪物,您在蓝月亮中调用过一次,具有三个元素,只是不在乎)。因此,为了实现现实世界的改进,我们理想地希望降低时间复杂度,或者如果未能降低最高级别的常数 k(或者换句话说,如果你可以开始做 n log n 次而不是 n² 次,那么就做,否则减少你正在做 n² 次的事情的成本,而不是你正在做 n 次的其他事情)。

换句话说,它可以帮助我们专注于通常最重要的事情。

【讨论】:

    【解决方案3】:

    不,if 不会影响复杂性。

    【讨论】:

      【解决方案4】:

      时间复杂度相同,打印 Yayyyy N^2 次。

      【讨论】:

        【解决方案5】:

        简答:运行时间仍然是 O(N^2)。

        长答案:条件检查的成本可以安全地“添加”到 println 操作的权重中,就像您有两个 println() 而不是执行一个 println()。 (关于这个例子,请记住,像 println 这样的 I/O 操作的成本大大超过了简单的整数比较。)

        也许您可以说 println() 调用花费“1 次操作”,而比较是“0.0001 次操作”,因此总成本将是“(1.0001 * N)^2 次操作,而不仅仅是 N^2。您还将 println() 的数量减少了一半,所以我们可以说您在 (1.0001 * N) ^ 2 / 2 次操作。这仍然是 O(N^2),即使对于给定 N 值,您可能通过只打印一半条目将运行时间减半。

        一般来说,比较的成本应该添加到由比较产生的分支内的操作成本中。当 if() {} 和 else {} 都存在时,测量运行时可能会更加困难。这里的一个策略是估计运行时间,就好像最昂贵的操作发生每次;或者,如果单个分支的运行时间不容易知道,则估计 both 操作在每次循环迭代中都发生。如果这些操作都是 O(1),那么你的运行时间顺序仍然是 O(N^2),因为你是线性缩放的。

        【讨论】:

        • 即使比较采用“1 次操作”:(2N)^2 = 4N^2 仍然是 N^2 复杂度。
        【解决方案6】:

        当然,如果您使用的是基于比较的算法,那您算对吗?

        所以在您的情况下,您正在查看 O(n2),因为您的 if 语句几乎被执行 n2 次。

        对于非比较算法,你计算你的主要操作。

        【讨论】:

        • @DavidHeffernan 他输入了O(n**2)。注意斜体字。
        猜你喜欢
        • 2021-03-20
        • 2020-09-16
        • 2020-06-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多