【发布时间】:2011-01-28 17:37:09
【问题描述】:
只有一个循环的程序的复杂度是多少,是 log n 吗? 有人可以给我一些关于估计代码复杂性的想法吗?
【问题讨论】:
-
循环次数并不是唯一重要的事情。所以,最好展示代码本身。
-
另外,复杂性是什么意思?听起来您可能指的是通常的 O() 时间复杂度表示法,但这只是一种复杂度。
只有一个循环的程序的复杂度是多少,是 log n 吗? 有人可以给我一些关于估计代码复杂性的想法吗?
【问题讨论】:
嗯,这真的取决于那个循环中发生了什么。
这个循环是线性时间,即O(n):
int sum = 0;
foreach( int i in SomeCollection )
{
sum += i;
}
但是,考虑一个在每次迭代期间执行子字符串搜索的循环。现在您必须考虑字符串搜索算法的复杂性。你的问题目前无法回答。如果您想要一个有意义的答案,您将需要提供一个代码示例。
【讨论】:
有一个研究领域试图准确地量化这一点。
在这种情况下,我相信您的复杂度等级将是 p = 2,因为循环是有条件的,这意味着该方法有两条路径。
如果您指的是time complexity,它仍然只是 O(1),除非循环迭代计数是通过多项式或指数函数得出的,可能间接因为该方法本身在更高的循环中被调用,或者因为循环计数器有效地乘以字符串操作或较低级别的东西。
【讨论】:
要获得一段代码的 Big-O 复杂度,您需要问自己“完成了多少次迭代”?
当然,问题在于,从代码本身中找出它并不总是那么容易,有时最好看大局并计算完成的操作量。
例子:
For (i = 0 ; i < n ; i++ ) {
//Do stuff
}
这是 复杂度
For (i = n ; i > 0 ; i= i/2 ) {
//Do stuff
}
这是一个 复杂度...因为在每次迭代中,我都会被减半。
void Mess (int n) {
for (i = 0 ; i < n ; i++) {
//Do stuff
Mess(n-1);
}
}
现在这看起来像一个简单的循环,因为它用递归调用自己,实际上是一团糟......每次迭代都用 n-1 调用自己 n 次。
所以在这里从最后开始思考会更容易。如果 n == 1 ,则有 1 次迭代。如果 n == 2 那么它会调用前一个场景两次。
所以如果我们调用函数,我们可以看到我们会递归得到什么:
最后当然会给我们n!
底线,它并不总是微不足道的。
【讨论】:
如果只有一个循环,它可能是循环体执行的次数......当然,在库调用中可能有很多隐藏循环。很容易创建一个循环执行 n 次 O(n^2) 或更糟,如果你有 strlen、memcpy 等发生在循环体内。
或者更糟糕的是,如果您有一个带有正则表达式的库(或语言),并且它们的正则表达式实现是幼稚的(如 Perl),那么只需一个循环 O(2^n) 就可以很容易地制作一个程序!正确编写的正则表达式实现不会发生这种情况。
【讨论】:
您可以使用“trend-prof”(https://pdfs.semanticscholar.org/8616/7f320e230641299754e0fbd860c44f5895f0.pdf)等工具轻松预测代码的计算时间和复杂度
Github 中提供了 GuessCompx 库,用于 R 代码的相同目的。
【讨论】:
如果您询问的是 Big-O 时间复杂度,那么 for 循环是循环内任何内容的 n 倍复杂度,其中 n 是循环计数限制。
所以。如果循环内的代码执行时间是固定的,即如果它的时间复杂度是O(1),那么循环的复杂度就是O(1*n) = O(n)。
以类似的方式,如果在循环中您有另一个循环将执行m 步骤,那么您的整个代码就是 O(n*m),依此类推。
【讨论】: