如何解决如何确定此代码中的最坏情况?
for(i=1;i<=n;i++) {
if((i&(i-1))==0) {
for(j=1;j<=i;j++) {
f();
}
} else {
f();
}
}
我对此代码做了一些测试用例,当i = 2 ^(i-1)执行第二个for时,如何确定大的O表示法,我认为它可能是O(n ^ 2)。 f()是O(1),如何获得摊销分析
解决方法
考虑何时(i&(i-1)) == 0
。对于2的幂才是正确的(更多详细信息,请参见this post)。小于n
的2的幂数是多少? log(n)
。对于log(n)
情况,将第二个循环重复i
次,而剩余成本为Theta(1)
。因此,时间复杂度为(w.l.o.g.假设n
是2的幂):
T(n) = n - log(n) // for i != 2^k
+ (1 + 2 + 2^2 + ... + 2^{log(n)}) // for i = 2^k
= n - log(n) + 2^{log(n)+1} - 1 = 3n - log(n) - 1 = Theta(n) // 2^log(n) = n
因此T(n) = Theta(n)
。
答案是n。
表达式( i & ( i - 1 ) ) == 0 )
仅在i为2的幂时才为true。因此,它将执行log2(n)次。
下一步是查找从内部循环调用f的次数。 i
的值是2的幂,其和被称为“几何级数”,维基百科has the formula。
除去一些常量,几何和与2 ^ N成比例,其中N是序列中元素的数量。在您的情况下,计数为log2(n),2 ^ log2(n)== n。
else
块也将被称为O(n)次。
所以我实际上对此进行了测试,这是n
的意思,因为您以对数(n)的速率达到2的幂,但是每次您达到1的幂都会使输出爆炸2 ^ n。如果它不是2的幂,那么它也是n。
这是我跑的东西
#include <iostream>
#include <string>
int main()
{
int n = 1000000;
int count = 0;
for(int i=1;i<=n;i++){
if((i&(i-1))==0){
for(int j=1;j<=i;j++){
count++;
std::cout << i << "," << j << ":" << count << std::endl;
}
}else{
count++;
std::cout << i << ":" << count << std::endl;
}
}}
对于所选值:
10:21
100:220
1000:2013
10000:26369
100000:231054
1000000:2048555
我并不是说运行程序是绝对的答案,只是这是一项有用的检查,即您没有完全离开(例如,如果是n ^ 2或恒定时间)。如您所见,每次输入的10倍或多或少都会对输出产生影响。如果它是n ^ 2,那么最后一行将是第一行的10 ^ 10。如果它是常数,则它将与第一个相似。登录约110万次。
,当i
是2
的幂时,内部循环将准确地执行对i
的{{1}}调用。否则,只有一个电话。
如果f
是n
的幂,让2
,我们总共有
2^m
打来电话,这是
1 + 2 + 4 + ... n + n - m
(在主循环的每次迭代中)平均来说,这3n - 1 - lg(n).
渐近。
现在,如果将3
与n = 2^m + n'
一起使用,则计数为
n' < 2^m
这笔款项仍在1 + 2 + 4 + ... + 2^m + 2^m + n' - m = 3.2^m - 1 + n' - m = 3.n - 2.n' - 1 - Lg(n - n')
中摊销,但更糟的是下降到3
了。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。