计算斐波那契的递归调用次数,用C表示

时间:2017-01-04 20:38:35

标签: c

我遇到了以下问题:

调用fib(8)(下面),进行了多少次递归调用(忽略第一次)?什么是回报值?

int fib (int n) {
    if (n==0 || n==1) return 1;
    else return fib(n-1) + fib(n-2);
}

所以我做了:

#include <stdio.h>
#include <stdlib.h>

int r = 0;

int fib (int n) {
    printf("k: %d fib n: %d", r++, n);
    if (n==0 || n==1) {
        printf("\n");
        return 1;
    } else { 
        printf(" +\n");
        return fib(n-1) + fib(n-2); 
    }
}

int main(int argc, char **argv) {
    int n = atoi(argv[1]);
    int f = fib(n);
    printf("\nreturn: %d\n", f);
    return 1;
}

使用此我将回复fib(8) = 34递归调用的数量为66

我是对的吗?

2 个答案:

答案 0 :(得分:2)

  

我是对的吗?

这是查看结果的简便方法:

> ./fib 8 | grep "k:" | wc -l
67

也就是说,我在命令行运行程序并将输出传送到grep以过滤输出。由于每次调用fib()只生成一个包含k:...的输出行,因此这些行的数量应与fib()函数的调用数相同。我进一步将输出从grep传送到wc -l,计算行数,结果为67。

正如@weathervane在评论中指出的那样,将r++更改为++r会增加r,然后在printf()来电中对其进行评估,这样您就可以了获得正确的值显示。或者,您可以查看输出并注意您从0开始计算:

k: 0 fib n: 8 +
k: 1 fib n: 7 +
k: 2 fib n: 6 +
k: 3 fib n: 5 +
...

由于您的点数从零开始,您必须添加一个才能得到总数。

答案 1 :(得分:2)

首先,总的fib调用= 67

递归调用是= 66

                   fib(5)   ---root-first call ,not consider recursive call 
                 /           \     
           fib(4)             fib(3)   
         /      \                /     \
     fib(3)      fib(2)       fib(2)    fib(1)
    /     \        /    \       /    \  

- 因为第一次通话不被视为递归通话

现在让我们推导一个计算fib(n)被称为

的次数的公式

设f(n)为计算fib(n)的调用次数。

如果n < 2然后f(n)= 1。

否则,f(n)= 1 + f(n-1)+ f(n-2)

因此,f至少为O(fib(n))。实际上,f(n)是2 * fib(n)-1。

我们通过归纳来证明这一点:

基本情况(n <2,即n = 0或n = 1):

f(n)= 1 = 2 * 1 - 1 = 2 * fib(n)-1。

诱导步骤(n> = 2):

f(n + 1)= f(n)+ f(n-1)+ 1

f(n + 1)= 2 * fib(n) - 1 + 2 * fib(n - 1) - 1 + 1

f(n + 1)= 2 * fib(n + 1)-1

实施例

fib(8)= 34

所以递归调用= 2 * 34-1 = 67

ans = 67-1(第一次通话)

FIB(4)= 5

所以递归调用= 2 * 5-1 = 9

ans = 9-1(第一次通话)

还可以以o(logn)

计算fib(n)

所以整体复杂度降低到o(logn)

O(logn)用于查找fib(n)和O(1)以查找递归调用

但您的代码需要指数时间