如何计算递归算法的时间复杂度?
int pow1(int x,int n) { if(n==0){ return 1; } else{ return x * pow1(x, n-1); } } int pow2(int x,int n) { if(n==0){ return 1; } else if(n&1){ int p = pow2(x, (n-1)/2) return x * p * p; } else { int p = pow2(x, n/2) return p * p; } }
分析递归函数(甚至评估它们)是一项艰巨的任务。(在我看来)很好的介绍可以在Don Knuths ConcreteMathematics中找到。
但是,让我们现在分析这些示例:
我们定义了一个函数,该函数为我们提供了函数所需的时间。假设t(n)表示所需的时间pow(x,n),即的函数n。
t(n)
pow(x,n)
n
然后可以得出结论,t(0)=c因为如果调用pow(x,0),我们必须检查(n==0),然后返回1,这可以在恒定时间内完成(因此,为常数c)。
t(0)=c
pow(x,0)
n==0
c
现在我们考虑另一种情况:n>0。在这里我们得到t(n) = d + t(n-1)。这是因为我们必须再次检查n==1,计算pow(x, n-1,因此(t(n-1))并将结果乘以x。校验和相乘可以在需要d递归计算的恒定时间(constant )中完成。pow``t(n-1)
n>0
t(n) = d + t(n-1)
n==1
pow(x, n-1
t(n-1)
x
d
pow``t(n-1)
现在我们可以“扩展”该术语t(n):
t(n) = d + t(n-1) = d + (d + t(n-2)) = d + d + t(n-2) = d + d + d + t(n-3) = ... = d + d + d + ... + t(1) = d + d + d + ... + c
那么,直到我们到达需要多长时间t(1)?由于我们从开始t(n)并在每一步中减去1,因此需要n-1步骤才能达到t(n-(n-1)) = t(1)。另一方面,这意味着我们得到n-1常数的乘积d,并被t(1)评估为c。
t(1)
n-1
t(n-(n-1)) = t(1)
因此我们获得:
t(n) = ... d + d + d + ... + c = (n-1) * d + c
所以我们得到的t(n)=(n-1) * d + c是O(n)的元素。
t(n)=(n-1) * d + c
pow2可以使用Masters定理完成。因为我们可以假设算法的时间函数是单调增加的。因此,现在我们有时间t(n)计算pow2(x,n):
pow2
pow2(x,n)
t(0) = c (since constant time needed for computation of pow(x,0))
因为n>0我们得到
/ t((n-1)/2) + d if n is odd (d is constant cost) t(n) = < \ t(n/2) + d if n is even (d is constant cost)
可以将以上内容简化为:
t(n) = floor(t(n/2)) + d <= t(n/2) + d (since t is monotonically increasing)
因此,我们获得t(n) <= t(n/2) + d,这可以使用大师定理来解决t(n) = O(log n)(请参阅Wikipedia链接中的“流行算法的应用”部分,例如“二进制搜索”)。
t(n) <= t(n/2) + d
t(n) = O(log n)