【问题标题】:How does this implementation of Fibonacci(n) work? [recursion]Fibonacci(n) 的这种实现是如何工作的? [递归]
【发布时间】:2011-12-15 06:21:51
【问题描述】:

我正在阅读的一本 Java 书籍中的一个练习让我感到困惑:

斐波那契数列是数字 1、1、2、3、5、8、 13、21、34 等,其中每个数字(从第三个开始)都是总和 前两个中的。创建一个将整数作为参数的方法 参数并显示从 开始。例如,如果您运行 java Fibonacci 5(其中 Fibonacci 是 类的名称)输出将是:1、1、2、3、5。

我本可以发誓它需要一个数组或某种方式来存储以前的数字,但是当我看到答案时,情况并非如此:

import java.util.*; 

public class Fibonacci { 

    static int fib(int n) {
         if (n <= 2) 
              return 1;

         return fib(n-1) + fib(n-2);
    } 
    public static void main(String[] args) {
    // Get the max value from the command line: 
    int n = Integer.parseInt(args[0]); 
    if(n < 0) {
        System.out.println("Cannot use negative numbers"); return;
    } 
    for(int i = 1; i <= n; i++)
        System.out.print(fib(i) + ", ");
    }
}

有人能解释在其内部使用函数是如何产生这种情况的吗?

【问题讨论】:

  • 在自身内部使用函数称为recursion
  • 了解递归的最好方法是学习递归。
  • 学习递归的最好方法就是去做,不要想花哨的名字。想象一下你是编译器/虚拟机,你正在运行程序。感受堆栈的存在。达到禅意。
  • 真的建议以n(可能是 4 或 5)的低值“玩电脑”。跟踪准确代码运行时发生的情况。努力得到了回报。
  • 这是一个递归解决方案。这也是一个糟糕的解决方案,除非您想要最小化效率。请注意,它不断地重新计算以前的 fib 数字。线性解决方案更好。

标签: java recursion fibonacci


【解决方案1】:

您提供的代码是 recursive 解决方案的示例。当函数第一次被调用时,它会一直执行,直到它调用自己。它的状态存储在堆栈中,并且代码开始使用新的输入数据再次执行。这个过程一直重复,直到输入小于 2,此时返回 1,并且答案返回给前一个调用者。

例如,调用 fib(5) 会导致以下执行:

fib(5):
    fib(4):
        fib(3):
            fib(2): 1
            fib(1): 1
        fib(2): 1
    fib(3):
        fib(2): 1
        fib(1): 1

请注意,您部分正确。在此解决方案中,中间结果存储在stack 上。这就是递归解决方案如此昂贵的原因之一。另一个是它的O(2^n) 复杂性。但是,如果可以迭代计算 Fibonacci(n) 并且不存储 all 以前的结果。您真正需要的只是将最后一个存储到结果中并从 1 计数到 n

【讨论】:

  • 没必要仅仅因为他比上一篇慢了 30 秒就给他投票! +1 顺便说一句:也许将标题更改为更有意义的内容,例如“理解斐波那契数列”并不是一个坏主意。
【解决方案2】:

这是一个递归解决方案。递归函数调用自身,直到满足给定的停止条件。然后每个呼叫退出,直到只剩下第一个呼叫。第一次调用会输出结果。

在您的解决方案中,停止条件是:

if (n <= 2) 
          return 1;

在满足此条件之前,该函数将对其自身进行连续调用。每次调用都会减少作为参数传递的 int。当它达到 2 时,停止条件指示函数返回值 1(fibonacci(n) 中 n=1 和 n=2 的结果)。

因为斐波那契是最后两个数之和,函数的递归部分,

return fib(n-1) + fib(n-2);

求和 n-1 和 n-2 (正如我所说,序列的最后两个数字)。当 n 等于 2 时,这些对函数 fib 的调用最终都会有一个值,并且会被返回。

例如,如果 n = 3,递归部分会调用 fib(2) 和 fib(1),两者都等于或小于 2,所以两个调用都会返回 1。所以 printf 会打印 1,1,2 . 2 是 1 + 1 的总和(我知道这很明显,但有时说明明显的帮助)。

【讨论】:

    【解决方案3】:

    这是recursive function 的标准示例。

    Fibonacci Numbers 也被声明为递归的。

    fib(1)fib(2) 都被声明为 1。所有其他的都是通过添加最后两个斐波那契数来计算的,所以 fib(3)=fib(2)+fib(1)

    将此与执行此操作的计算方法进行比较:

    static int fib(int n) {
         if (n <= 2) 
              return 1;
    
         return fib(n-1) + fib(n-2);
    } 
    

    顺便说一下,这是一种非常慢的方法来计算斐波那契数,使用两个变量(最后一个不需要所有变量,只需要最后两个!)并且循环在 O(n ),上面的递归函数有 O(2^n) 次操作。

    【讨论】:

      【解决方案4】:
                                 F(n)
                                  /    \
                              F(n-1)   F(n-2)
                              /   \     /      \
                          F(n-2) F(n-3) F(n-3)  F(n-4)
                         /    \
                       F(n-3) F(n-4)
      

      需要注意的重要一点是该算法是指数型的,因为它不存储先前计算的数字的结果。例如 F(n-3) 被调用了 3 次。

      更多细节请参考 dasgupta 第 0.2 章的算法

      【讨论】:

        猜你喜欢
        • 2013-10-28
        • 2014-12-18
        • 1970-01-01
        • 2016-05-14
        • 2013-03-20
        • 2011-05-30
        • 2019-01-05
        • 2011-01-25
        • 2020-03-13
        相关资源
        最近更新 更多