这个递归Fibonacci的大时间复杂度?

时间:2017-12-18 14:57:29

标签: time-complexity big-o complexity-theory asymptotic-complexity code-complexity

我有一个使用递归打印斐波那契数列的程序。有更好的方法,但我被要求使用递归,所以我必须这样做。

以下是该计划:

#include <stdio.h>
#define TERMS 10

long fibo(int);

int main(void){
   for(int i = 1; i <= TERMS; i++) {
       printf("%ld", fibo(i));
   }
   return 0;
}

long fibo(int n){
    if (n < 3) {
        return 1;
    }
    else {
        return fibo(n - 1) + fibo(n - 2);
    }
}

我知道这对斐波那契系列来说真是一个糟糕的方法,从上面可以清楚地看出, TERMS 超过35,该程序需要花费大量时间才能完成。

我经历过this answer并无法理解他们是如何解决的,但看起来像是

  

fibo(int n)的时间复杂度为O(2 ^ n)

我可能也完全错了,但我想要的只是:

这个完整计划的时间复杂度是什么,请简要说明您的计算方法?

如果您有更好的方法使用递归计算Fibonacci,也欢迎。

3 个答案:

答案 0 :(得分:5)

  

c(fibo(n))= c(fibo(n - 1))+ c(fibo(n - 2))+ O(1)

请注意,复杂性遵循精确的公式作为序列,因为所有计算分支总是以值为1的叶结束,因此精确的(theta)复杂度可以通过Fibonacci序列本身的闭合公式精确计算

Fibonnaci closed formula

但这超出了您的问题的范围,我们需要注意的是

  

c(fibo(n))&lt; 2 * c(fibo(n - 1))

我们现在需要的是解决由

定义的上限序列
  

an = 2 * an-1(a1,2 = 1)

结果

  

an = 2 ^ n

所以,你得到你想要的2 ^ n的上限O。

如果你多次运行,你会得到

  

sigma(c(fib(n)))从1到TERMS = O(2 ^(TERMS + 1) - 1)

这是一个简单的数学事实,意味着在你的情况下(TERMS = 10)你得到

  

2 ^ 11 - 1 = 2047

至于你提出的关于更好地以递归方式做这件事的问题......

int fib(int n, int val = 1, int prev = 0)
{
    if (n == 0) {
        return prev;
    }
    if (n == 1) {
        return val;
    }
    return fib(n - 1, val + prev, val);
}

这就是所谓的尾递归并且需要O(n)(实际上它可以通过一个好的编译器来优化,实现为一个循环,然后也会耗尽一个恒定的内存消耗)

答案 1 :(得分:4)

总的来说,背后有数学,斐波那契在那里解释:https://en.wikipedia.org/wiki/Recurrence_relation

如果您不必证明它并且您只需要正确地写下来,您只需要考虑算法的行为方式以及某些数字的重复次数,然后您可以尝试将其概括为任何数字。输入n

纸是你的朋友!

如果你的递归中你的斐波纳契值为“10”,你基本上就是说(10的finonacci是9 +斐波纳契的斐波那契8)

然后你说斐波那契9 - 它是斐波那契8 +斐波纳契7等。

您可以绘制图表:

enter image description here

我认为很明显它会继续几乎完整的二叉树。并且您可以看到,对于每个级别,节点数量加倍,因此对于fib(10),它将重复10次,在底部几乎2^10,因此对于fib(n),它将是2^n {1}}。

如何使它在递归的alghoritm中有效?那么你可以从图片中看到,即fib(7)被解决了三次。所以你必须在计算后记住fib(n)。它可以是全局变量,也可以通过递归调用传递对象的引用。

然后你不要只说“fib(n-1)和fib(n-2)”,你首先看“是否计算了fib(n-1)”?如果是这样,请使用计算出的值,而不是进行递归。

答案 2 :(得分:0)

用于生成斐波那契数列的递归函数生成高度为 n 的二叉树。假设我们取 n = 5。然后,树形结构将如下所示:

fib-recursion-tree

在最底层,我们将得到大约2 ^ n 个节点。因此,时间复杂度将在 O(2 ^ n)左右,因为递归将对每个叶节点重复。

我们可以通过使用备忘录的动态编程方法来显着改善此问题,该备忘录基本上是将重复的子问题(例如示例中的fib(2)fib(3)存储在某种查找表中)。这样可以将时间复杂度降低为 O(n)