6

好的,我最初编写了一个简单的代码来根据用户输入从系列中返回斐波那契数..

n=5 将产生 3..

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

我正在考虑修改代码以返回系列的总和,而不仅仅是从系列中返回值,并且在尝试求和时,我不小心在 return 语句中加了 1,令我惊讶的是,它正确地返回了总和。

对于 n=5,下面的代码将返回 7。

我不确定这是否是计算总和的正确方法......

如果我添加 1,我仍然无法弄清楚该系列的总和是如何工作的。有人可以解释一下吗?

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

编辑:

对于斐波那契数列..0,1,1,2,3,5,8,13,21,34,55,89,144....

我尝试了一些随机的 n

n=13

函数返回 376

0+1+1+2+3+5+8+13+21+34+55+89+144 = 376

n=10

函数返回 88

0+1+1+2+3+5+8+13+21+34= 88

4

6 回答 6

10

您对fibonacci程序的修改确实可以计算总和。但是,您使用递归的方式效率低下。解决这个问题的一种方法是使用“动态编程”方法,其中计算的值被缓存,以便它们可以被第二个递归调用重新使用。但是,第 n 个斐波那契数可以从基数向前计算。对此的递归实现将是:

public static int fib_r (int a, int b, int n) {
    if (n == 1) return a;
    if (n == 2) return b;
    return fib_r(b, a+b, n-1);
}

public static int fib (int n) {
    return fib_r(0, 1, (n > 0) ? n : 1);
}

总和的相应代码是:

public static int sumfib_r (int a, int b, int n) {
    if (n == 1) return a;
    if (n == 2) return b;
    return sumfib_r(b, a+b+1, n-1);
}

public static int sumfib (int n) {
    return sumfib_r(0, 1, (n > 0) ? n : 1);
}

作为尾调用删除的一部分,编译器/解释器通常会将尾递归更改为一个简单的循环。

您询问:

如果我添加 1,我仍然无法弄清楚该系列的总和是如何工作的。有人可以解释一下吗?

这个问题实际上是关于理解算法,我认为这是关于 SO 的主题。但是,需要数学来描述该算法为何起作用。所以,这真的是一道数学题。关于斐波那契数之和有一个众所周知的定理。如果F[i]是第 i 个斐波那契数,并且S[n]是第一个n斐波那契数的和,则上述定理指出:

    S[n] = F[n+2] - 1

因此,如果我们根据 的定义考虑S[n+2]

S[n+2] = S[n+1] + F[n+2]

然后,替换S[n] + 1F[n+2]

S[n+2] = S[n+1] + S[n] + 1

您应该认识到的是您的“添加 1 个修改”fibonacci功能。


下面是一个归纳证明,您的程序计算了我在原始答案中提供的总和。让F代表您的fibonacci功能,并让S代表您的“添加 1 个修改”fibonacci功能。

F[1] = 0
F[2] = 1
F[i] = F[i-1] + F[i-2] for i > 1

S[1] = 0
S[2] = 1
S[i] = S[i-1] + S[i-2] + 1 for i > 1

然后,您需要一个证明k > 0

         k
       .---  
S[k] =  >   F[i]
       `---
       i = 1

请注意,当且仅当:

S[1] = F[1]
S[k] = F[k] + S[k-1] for k > 1

证明是相当直接的。基本情况是微不足道的。

S[1] = F[1] = 0
S[2] = F[2] + F[1] = 1
S[3] = S[2] + S[1] + 1 = F[3] + F[2] + F[1] = 2

归纳步骤是: 鉴于对于一些k > 2S[j+1] = F[j+1] + S[j]对于0 < j < k+1,证明等式成立,如果j = k+1,即:S[k+2] = F[k+2] + S[k+1]

    S[k+2] = S[k+1] + S[k] + 1
=>  S[k+2] = (F[k+1] + S[k]) + (F[k] + S[k-1]) + 1
=>  S[k+2] = (F[k+1] + F[k]) + (S[k] + S[k-1] + 1)
=>  S[k+2] = F[k+2] + S[k+1]

这样就完成了证明。

于 2013-03-13T20:13:06.613 回答
3

不,不会的。代码的第二个版本计算斐波那契函数的所有值的总和,直到给定值。基本情况也是错误的!

如果要递归计算总和,请将问题分成两部分,如下所示:

public static int fib(int n) {
    return n < 2 ? n : fib(n-1) + fib(n-2);
}

public static int sumfib(int n) {
    return n < 0 ? 0 : fib(n) + sumfib(n-1);
}

第一个函数计算斐波那契,第二个函数负责将值相加到给定的数字。

于 2013-03-13T19:50:41.700 回答
1

正确的做法是使用累加器。

代码应该看起来像这样(我没有检查它,这只是想法)

static int fibonacci(int n, int accumlator) {
    if (n == 1)
        return 0;
    else if (n == 2)
        return 1;
    else
        accumlator = (fibonacci(n - 1, accumlator) + fibonacci(n - 2, accumlator));
        return accumlator;
}
于 2013-03-13T20:46:51.977 回答
0

您的代码需要测试n<1- 如果您传递 0 或更少的参数,它将永远持续下去......

除此之外 - 如果您致电fib(5),会发生以下情况:

...
return(fib(4) + fib(3))

fib(4):
return(fib(3) + fib(2))

fib(3):
return(fib(2) + fib(1))

now fib(2) == 1 by your definition, and fib(1) == 0

so fib(3) == 1

then fib(4) == 1 + 1 = 2

and fib(5) = fib(4) + fib(3) = 2 + 1 = 3

Now if you add the '+1', the following happens:

fib(1) and fib(2) are unchanged
fib(3) = 1 + 0 + 1 = 2
fib(4) = fib(3) + fib(2) + 1 = 4
fib(5) = fib(4) + fib(3) + 1 = 4 + 2 + 1 = 7

您的原始方法很好,但这取决于您如何考虑斐波那契数的“顺序”(您希望第一个数字是什么)。

于 2013-03-13T19:53:09.890 回答
0

递归是计算斐波那契数的一种非常低效的方法。在数字 43 之后,需要 30 多秒才能得到答案。我试图找出计算数字 52 需要多少时间,大约需要 47 分钟。所以时间增长得非常快。

递归代码:

private int calculateRecursivelyInt(int fnum)
    {
        if (fnum == 0)
            return 0;
        if (fnum == 1)
            return 1;

        return calculateRecursivelyInt(fnum - 1) + calculateRecursivelyInt(fnum - 2);
    }

循环效率更高

    //This method will be able to calculate till the F46 because int can't hold a 
    // bigger number. You can calculate till 92 with a type long and till 93 with
    // unsigned long in C#.

    private int calculateLoopInt(int num)
    {
        int fnum = 0;
        int val1 = 0;
        int val2 = 1;

        for (int i = 0; i < num; i++)
        {
            if (num == 1)
                fnum = 1;
            else if (i > 0)
            {
                fnum = val1 + val2;
                val1 = val2;
                val2 = fnum;
            }
        }
        return fnum;
    } 
于 2013-10-19T22:27:14.757 回答
0

另一种使用递归函数打印斐波那契数列的方法。

#include <iostream>

// 0 1 1 2 3 5 8 13...
//

void fibb (int idx, int curr = 0, int next = 0)
{
        std::cout << curr << ", ";
        if(!idx) return;
        if(curr == 0) {
                curr = 1;
                fibb(--idx, curr, next);
                return;
        }
        next += curr;
        fibb(--idx, next, curr);
}


int main()
{
        fibb(10);
}
于 2017-12-05T17:10:59.503 回答