所以我想知道如何根据操作次数计算出一段代码的时间复杂度( T(n)),例如下面的代码。< / p>
for( int i = n; i > 0; i /= 2 ) {
for( int j = 1; j < n; j *= 2 ) {
for( int k = 0; k < n; k += 2 ) {
... // constant number of operations
}
}
}
我确信它很简单,但我的讲师并没有很好地教授这个概念,我真的想知道如何计算时间的复杂性!
提前谢谢!
答案 0 :(得分:1)
为了解决这个问题,一种方法是逐个分解三个循环的复杂性。
我们可以做的一个重要观察是:
(P):每个循环中的步数不依赖于其父循环的“索引”的值。
我们打电话
f(n)
外部循环(1)g(n)
h(n)
位于最内圈(3)。
for( int i = n; i > 0; i /= 2 ) { // (1): f(n)
for( int j = 1; j < n; j *= 2 ) { // (2): g(n)
for( int k = 0; k < n; k += 2 ) { // (3): h(n)
// constant number of operations // => (P)
}
}
}
步数
i
获取值n
,n/2
,n/4
,...等,直到n/2^k
2^k
大于{{{{}} 1}}(n
),这样2^k > n
,此时你退出循环。
另一种说法是你有步骤1(n/2^k = 0
),步骤2(i = n
),步骤3(i = n/2
),......步骤{{1} }(i = n/4
),然后退出循环。这些是k - 1
步骤。
现在i = n/2^(k-1)
的价值是多少?观察k
。这会使k
或松散地说n - 1 <= 2^k < n <=> log2(n - 1) <= k < log2(n) <= INT(log2(n - 1)) <= k <= INT(log2(n))
。
每个步骤的费用
现在每个步骤有多少次操作?
在步骤k = INT(log2(n))
,根据我们选择的符号和属性(P),它是k = log2(n)
。
步数
你有步骤(1)(i
),步骤(2)(g(i) = g(n)
),步骤(3)(j = 1
)等等,直到你到达步骤(p)({{ 1}})其中j = 2
被定义为j = 4
的最小整数,或松散地说j = 2^p
。
每个步骤的费用
根据我们选择的符号和属性(P),步骤p
的费用为2^p > n
。
步数
我们再次计算步骤:(1):log2(n)
,(1):j
,(2):h(j) = h(n)
,...,k = 0
。这相当于k = 2
步。
每个步骤的费用
由于(P),它是常数。我们称之为常数k = 4
。
汇总操作的数量是
k = n - 1 or k = n - 2
所以n / 2
答案 1 :(得分:0)
编写方法,添加计数器,返回结果:
int nIterator (int n) {
int counter = 0;
for( int i = n; i > 0; i /= 2 ) {
for( int j = 1; j < n; j *= 2 ) {
for( int k = 0; k < n; k += 2 ) {
++counter;
}
}
}
return counter;
}
快速增加N的协议,并以可读的方式记录结果:
int old = 0;
for (int i = 0, j=1; i < 18; ++i, j*=2) {
int res = nIterator (j);
double quote = (old == 0) ? 0.0 : (res*1.0)/old;
System.out.printf ("%6d %10d %3f\n", j, res, quote);
old=res;
}
结果:
1 0 0,000000
2 2 0,000000
4 12 6,000000
8 48 4,000000
16 160 3,333333
32 480 3,000000
64 1344 2,800000
128 3584 2,666667
256 9216 2,571429
512 23040 2,500000
1024 56320 2,444444
2048 135168 2,400000
4096 319488 2,363636
8192 745472 2,333333
16384 1720320 2,307692
32768 3932160 2,285714
65536 8912896 2,266667
131072 20054016 2,250000
因此n增加了2倍,计数器在开始时增加超过2 2,但随后迅速减少到某个东西,不会高于2.这可以帮助您找到方法。