我在StackOverflow上搜索了一下,并且已经理解了j循环的复杂性,即O(n2)
。然而,随着嵌套添加k循环,我很困惑为什么复杂性变为O(n3)
。有人能帮助我理解这个吗?
根据我的理解,i-loop有n次迭代,j-loop有1 + 2 + 3 + ... + n次迭代n*(n+1)/2
,即O(n2)
。
for(i = 1; i < n; i++) {
for(j = i+1; j <= n; j++) {
for(k = i; k <= j; k++) {
// Do something here...
}
}
}
编辑:感谢所有帮助人员:) Balthazar,我写了一段代码,根据它们所处的循环增加计数器,有点粗略的步骤 - 步骤:
#include <iostream>
int main(int argc, const char * argv[])
{
int n = 9;
int index_I = 0;
int index_J = 0;
int index_K = 0;
for (int i = 1; i < n; i++) {
for (int j = i+1; j <= n; j++) {
for (int k = i; k <= j; k++) {
index_K++;
}
index_J++;
}
index_I++;
}
std::cout << index_I << std::endl;
std::cout << index_J << std::endl;
std::cout << index_K << std::endl;
return 0;
}
我将此代码从n = 2运行到n = 9,增量为1,并且得到以下序列:
从柜台,可以看出:
i = n-1给出O(n)和j =((n-1)* n)/ 2的复杂度,给出复杂度O(n2)
。 K的模式难以发现,但众所周知K取决于J,因此:
k = ((n+4)/3)*j = (n*(n-1)*(n+4))/6
复杂度为O(n3)
我希望这将有助于将来的人们。
EDIT2:感谢Dukeling格式化:)在最后一行发现了一个错误,现在更正了
答案 0 :(得分:12)
如果你已经习惯了Sigma Notation,这是一种推断算法时间复杂度的正式方法(精确的嵌套循环):
注意:公式简化可能包含错误。如果您发现任何问题,请告诉我。
答案 1 :(得分:5)
k循环具有O(j-i)复杂度
j循环具有O((n-i)*(n-i))复杂度
i-loop具有O(n * n * n)= O(n ^ 3)复杂度
无论如何,你知道它不是O(n ^ 2),因为前两个循环是O(n ^ 2)并且它不超过O(n ^ 3),因为只有3个循环
答案 2 :(得分:1)
请查看this示例,以评估最坏情况的复杂性。
本质上,如果你逐行评估它,你会得到类似O(n ^ 3 / C)的东西,其中C是一些常数,通常在这样的评估中被跳过,导致O(n ^ 3)。
答案 3 :(得分:1)
在没有图表的情况下解释这是非常棘手的,但每个嵌套循环将在将迭代返回到父级之前迭代“n”次。
正如jambono所指出的,每个嵌套循环都需要对“n”的每次迭代进行比较/评估。因此将“n”与每个循环中的局部变量(n * n * n)进行比较,得到O(n ^ 3)。
将代码放入调试器中,以便直观地指示机器如何处理这种复杂性。
答案 4 :(得分:1)
首先,我们将考虑循环,其中内循环的迭代次数与外循环索引的值无关。例如:
for (i = 0; i < N; i++) {
for (j = 0; j < M; j++) {
sequence of statements
}
}
外循环执行N次。每次外循环执行时,内循环执行M次。因此,内循环中的语句总共执行N * M次。
因此,两个循环的总复杂度为O(N2)。
类似地,三个循环的复杂性是O(N3)