大O符号估计

时间:2016-05-24 20:58:47

标签: performance big-o benchmarking

不确定这是否是适合此类问题的地方,但现在就这样了。给出以下代码,有多少基本操作,以及每个操作执行了多少次。这个运行时间的最大符号是什么?如果重要的话,这是在MATLAB中。

total = 0;

for i = 1:n
    for j = 1:n
        total = total + j;
    end
end

我的想法是,对于每个n,j = 1:n循环运行一次。在j = 1:n循环内有n次计算。因此对于j = 1:n循环,其n ^ 2。这在i = 1:n循环内运行n次,因此计算的总量为n ^ 3,大O值为O(N ^ 3)。这是对的吗?

2 个答案:

答案 0 :(得分:1)

简短的回答是:

O(n^2)

长(简化)答案是:

大" O"是指算法的复杂性(在本例中是您的代码)。你的问题问了多少"执行循环或操作,但是" O"符号给出了算法复杂性的相对概念,因此不是绝对量。这完全是不切实际的,O符号的概念是概括了复杂性的度量,以便算法可以相对于另一个进行比较,而不必过多担心执行了多少分配,循环等。

话虽如此,但有关于如何计算算法复杂性的具体指导原则。一般为:

  • 循环具有复杂度O(" n"),无论它们执行多少迭代(记住,这是一个抽象的度量)。
  • 分配,添加等操作通常近似为O(1)(复杂度为1),因为它们执行的时间可以忽略不计。

if then else操作有一些具体规则,但会让事情变得更复杂,我邀请您阅读一些introduction material on performing algorithm complexity analysis

另外,要小心," n"不是在你的代码中使用的,它是一个特殊的符号,用于表示"泛型"线性复杂性。

测量算法的复杂性是一种递归操作。你从基本的操作开始,然后转到循环等等。所以,这里有一个详细的(我故意细节太多,所以你知道它是如何工作的,但在实践中你不必进入那个级别细节):

您从第一条指令开始:

O(total = 0;) = O(1)

因为这是一项任务。

然后:

O(total = total + j;) = O(total + j) + O(total = x)

其中xtotal + j的结果。

                      = O(1) + O(1)

这些是基本操作,因此它们的复杂度为1。

                      = O(1)

因为" O"是一个伟大的"伟大的"将任何常量之和视为1的指标。

现在进入循环:

O(
    for i = 1:n // O(n)
        for j = 1:n // O(n)
            total = total + j; // O(1)
        end
    end
)
=
O(
    n * ( 
        n * (
            1
        )
)
= O(n * n * 1)
= O(n^2)

如果连续有两个循环(对于......;对于......;),复杂度不是O(2n),而是O(n),因为O再次推广。

希望有所帮助:)

答案 1 :(得分:0)

您的分析是在正确的轨道上,但您高估了成本n倍。特别是,请看这里:

  

在j = 1:n循环内有n次计算。所以对于j = 1:n循环,它的n ^ 2。

你是对的,j = 1:n循环进行n次计算,但循环的每次单独迭代只进行1次计算。由于循环运行n次,所完成的工作是O(n),而不是O(n 2 )。如果你从那时起重复其余的分析,你最终会得到完成的总工作量是Θ(n 2 ),这比你之前的结果更紧密。

作为一个注释 - 你实际上可以非常显着地提高速度。请注意,内部循环将总计增加1 + 2 + 3 + ... + n。我们知道1 + 2 + 3 + ... + n = n(n + 1)/ 2,所以你可以重写代码

total = 0;

for i = 1:n
     total = total + n * (n + 1) / 2;
end

但请注意,现在你只需添加n份n *(n + 1)/ 2,所以你可以将其重写为

total = n * n * (n + 1) / 2

并且整个过程需要时间O(1)。