递归算法的时间复杂度

时间:2010-04-25 17:15:11

标签: c algorithm time-complexity

如何计算递归算法的时间复杂度?

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;
    }
}

5 个答案:

答案 0 :(得分:37)

分析递归函数(甚至评估它们)是一项非常重要的任务。 A(在我看来)好的介绍可以在Don Knuths Concrete Mathematics中找到。

但是,让我们现在分析这些例子:

我们定义一个函数,为函数提供所需的时间。假设t(n)表示pow(x,n)所需的时间,即n的函数。

然后我们可以得出结论t(0)=c,因为如果我们调用pow(x,0),我们必须检查是否(n==0),然后返回1,这可以在恒定时间内完成(因此常数c)。

现在我们考虑另一种情况: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的{​​{1}}倍,d被评估为t(1)

所以我们获得:

c

所以我们得到t(n) = ... d + d + d + ... + c = (n-1) * d + c ,它是O(n)的元素。

t(n)=(n-1) * d + c可以使用Masters theorem完成。因为我们可以假设算法的时间函数是单调递增的。现在我们有pow2计算所需的时间t(n)

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(参见维基百科链接中的流行算法应用,例如“二进制搜索”)。

答案 1 :(得分:11)

让我们从pow1开始吧,因为那是最简单的。

你有一个功能,在O(1)中完成一次运行。 (条件检查,返回和乘法是恒定时间。)

你剩下的就是你的递归。您需要做的是分析函数最终调用自身的频率。在pow1中,它会发生N次。 N * O(1)= O(N)。

对于pow2,它的原理是相同的 - 单个运行的函数在O(1)中运行。但是,这次你每次减半。这意味着它将运行log2(N)次 - 实际上每位运行一次。 LOG2(N)* O(1)= O(日志(N))。

可能对你有所帮助的是利用递归总是表示为迭代的事实(并非总是非常简单,但它是可能的。我们可以将pow1表达为

result = 1;
while(n != 0)
{
  result = result*n;
  n = n - 1;
}

现在你有一个迭代算法,你可能会发现以这种方式分析它更容易。

答案 2 :(得分:6)

它可能有点复杂,但我认为通常的方法是使用Master's theorem

答案 3 :(得分:5)

忽略递归的两个函数的复杂度是O(1)

对于第一个算法,pow1(x,n)的复杂度为O(n),因为递归深度与n线性相关。

第二个复杂度是O(log n)。这里我们大约递归log2(n)次。抛出2我们得到log n。

答案 4 :(得分:0)

所以我猜你是把x提升到了力量n。 pow1需要O(n)。

你永远不会改变x的值,但每次从n取1,直到它变为1(然后你只返回)这意味着你将进行n次递归调用。