【问题标题】:How did this get 8?这是怎么得到8的?
【发布时间】:2010-03-09 18:36:39
【问题描述】:

代码如下:

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

    public static void main(String[] arg) 
    {
        System.out.println(fibonacci(5));
    }
}

输出为 8。 输出应该是 8,但是当我看到这个时,我认为它应该是 7 ((5-1) +(5-2))。

为什么输出是 8?我认为获得 8 的原因可能会使递归不再让我感到困惑。

【问题讨论】:

  • 又一个“我的家庭作业”问题。
  • (5-1) 和 (5-2) 是您用来再次调用该方法的参数,而不是您添加和返回的值。
  • 你忘了这个stackoverflow.com/questions/2406824/… 吗? :)
  • 0, 1, 1, 2, 3, 5, 8, ... -- 你知道斐波那契数列是什么,不是吗? en.wikipedia.org/wiki/Fibonacci_number
  • @muxecoid 这不是我的作业。我正在尝试自学 Java,但我无法理解递归。

标签: java recursion fibonacci


【解决方案1】:

让我们把它当作代数,我会写f(n)而不是fibonacci(n)以节省空间:

f(5) = f(4) + f(3)
f(5) = f(3) + f(2) + f(2) + f(1)
f(5) = f(2) + f(1) + f(1) + f(0) + f(1) + f(0) + f(1)
f(5) = f(1) + f(0) + f(1) + f(1) + f(0) + f(1) + f(0) + f(1)
f(5) =  1   +  1   +  1   +  1   +  1   +  1   +  1   +  1

【讨论】:

  • 感谢这有很大帮助。当我写出来的时候,我得到了 5,但是当我读到这篇文章时,我意识到我忘记把 fib (0) 变成 1。谢谢
【解决方案2】:

因为是递归调用,所以每次调用参数不是0或者1的时候都会再次调用。

fibonacci(7)
-> fibonacci(6) // recursively calls itself with (7-1)
   -> fibonacci(5) // recursively calls itself with (6-1)
      -> fibonacci(4) // recursively calls itself with (5-1)
         -> fibonacci(3) // recursively calls itself with (4-1)
            -> fibonacci(2) // recursively calls itself with (3-1)
               -> fibonacci(1) // recursively calls itself with (2-1)
   -> fibonacci(4) // recursively calls itself with (6-2)
        ...
-> fibonacci(5) // recursively calls itself with (7-2)
   -> fibonacci(4) // recursively calls itself with (5-1)
      -> fibonacci(3) // recursively calls itself with (4-1)
         -> fibonacci(2) // recursively calls itself with (3-1)
            -> fibonacci(1) // recursively calls itself with (2-1)
   -> fibonacci(3) // recursively calls itself with (5-2)
      ...

等等。

想想这样的逻辑,你应该能够计算出它实际返回给初始调用者的内容。

【讨论】:

  • 它仍然没有意义抱歉。我看到你加粗了两个 4,但我不明白它们是从哪里来的。这两个 4 都是 5-1,但代码使它看起来像我上面所说的那样需要 5-1 和 5-2。
  • @David:阅读我的答案 - 我在每一步中都会遍历它......这有帮助吗?
  • @David:Reed Copsey 和 matt b 的回答提供了一个稍微不同的角度,应该会有所帮助。
【解决方案3】:

它返回的是fibonacci(n-1),而不是n-1。当你用 5 调用它时,你会得到:

return fib(4) + fib(3);

fib(4) 返回:

return fib(3) + fib(2);

fib(3) 返回:

return fib(2) + fib(1);

fib(2) 返回:

return fib(1) + fib(0);

一旦到达 fib(1) 或 fib(0),就返回 1;

向后工作,fib(2) 返回 2:

return 1 /*fib(1)*/ + 1 /*fib(0)*/;

同样的逻辑,fib(3) 返回 2 + 1,或者 3.Fib(4) 返回3 + 2,或者 5.Fib(5) 因此返回 5 + 3,也就是你的 8。

【讨论】:

    【解决方案4】:

    也许这个改编自Structure and Interpretation of Computer Programs(SICP,或向导书)的插图会有所帮助:

    切线切线,SICP 是一个非常深刻的编程入门,虽然有时很难。由于它使用 Lisp(而不是 Scheme)作为教学语言,因此自始至终都使用递归。甚至 Lisp 中的迭代过程也是基于递归调用的:

    (define (factorial n)
      (define (fact-iter n product)
        (if (> n 1) 
            (fact-iter (- n 1) (* product n))
            product
      ) )
      (fact-iter n 1)
    )
    
    (factorial 5)
    ; returns 120
    

    实际上是iterative。注意:car 返回列表的头部,而cdr 返回尾部。运营商使用prefix notation(- a b) 是“a - b”,(* a b) 是“a * b”。

    这是您的斐波那契程序在 Scheme 中的样子:

    (define (fibonacci n)
      (if (or (= n 1) (= n 2))
          1
          (+ (fibonacci (- n 1)) (fibonacci (- n 2)))
      )
    

    【讨论】:

    • lisp 和 Scheme 是什么意思?
    • Lisp (en.wikipedia.org/wiki/Lisp_%28programming_language%29) 是一个语言家族。该名称是“列表处理器”的缩写。 Scheme 是 Lisp 的一种。其他包括 Common Lisp、Emacs Lisp 和 Clojure。 Lisp 家族中的语言具有非常简单的语法(几乎所有内容都是包含在括号中并由空格分隔的列表),但功能非常强大。
    • xkcd 总结得很好:xkcd.com/297。另请参阅paulgraham.com/icad.html 的“Lisp 与众不同的原因”部分
    【解决方案5】:

    不是((5-1) + (5-2)),而是(finonacci(5-1) + fibonacci(5-2))

    finonacci(5-1) 减少为fibonacci(4),变成(finonacci(4-1) + fibonacci(4-2)),等等。

    【讨论】:

      【解决方案6】:
      return fibonacci (n-1) + fibonacci (n-2); 
      

      这实际上不仅仅是在做 (n-1) + (n-2),而是再次递归调用斐波那契函数。

      所以它在做斐波那契 (4) + 斐波那契 (3)。然后该 fib(4) 被评估为 fib(3) + fib(2),因此它最终返回 fib (3) + fib (2) + fib (3)。同样,这些 fib(3) 中的每一个实际上都是 fib (2) + fib (1),依此类推。它一直这样崩溃,直到它击中

      if (n == 0 || n == 1)
      

      所以它最终是一堆 fib (1) + fib (0) + fib (1)...,即 1 + 1 + 1...,如果你真的打破了,最终会变成 8一直向下。

      【讨论】:

        【解决方案7】:

        我还没有看到这种方法。假设您正在存储结果并构建它,其中f[i] 是调用fibonacci(i) 的结果。 0 和 1 是基本情况,其余的都以此为基础:

        f[0] = 1
        f[1] = 1
        f[2] = f[1] + f[0] = 1 + 1 = 2
        f[3] = f[2] + f[1] = 2 + 1 = 3
        f[4] = f[3] + f[2] = 3 + 2 = 5
        f[5] = f[4] + f[3] = 5 + 3 = 8
        

        【讨论】:

        • 第二个斐波那契数是 1
        【解决方案8】:

        函数的结果不是(5 - 1) + (5 - 2),而是fibonacci( 5 - 1 ) + fibonacci( 5 - 2 )fibonacci( 4 ) + fibonacci( 3 ),即5 + 3。顺序为:

        1 1 2 3 5 8

        0 1 2 3 4 5

        【讨论】:

          【解决方案9】:

          Recursion 实际上与proof by induction 的数学概念密切相关——事实上,斐波那契数列是递归定义的,所以在某种程度上你必须已经用递归的方式思考才能理解它是如何工作的。

          为了更好地理解代码,您可以应用beta reduction -- 即将每个函数调用替换为函数本身的主体。

          如果fibonacci(n) 转换为fibonacci(n - 1) + fibonacci(n - 2) 那么:

          fibonacci(5) = fibonacci(4) + fibonacci(3)
          fibonacci(5) = (fibonacci(3) + fibonacci(2)) + (fibonacci(2) + fibonacci(1))
          

          很容易看出这将永远持续下去,除非我们做了特殊情况。在这里,我们知道fibonacci(1) 转换为1fibonacci(0) 也转换为1。所以我们一直在减少 beta,直到我们只剩下一个,看起来像:

          fibonacci(5) = ((1 + 1) + (1 + (1 + 1))) + ((1 + 1) + 1)
          

          因此:

          fibonacci(5) = 8
          

          【讨论】:

            【解决方案10】:

            第一个斐波那契数是 1,1,2,3,5,8,... 任何其他数字都是意料之外的。

            【讨论】:

            • 它是 8 的原因与它是斐波那契数无关。 “fibanacci numbers”是一组数字的强加特征。它返回一个 8 是语义上程序含义的结果。它不返回 8,因为它应该返回,因为我希望它返回斐波那契数
            • @David “它是 8 的原因与它是斐波那契数无关”。我以为你写了一个名为 fibonacci 的函数来计算斐波那契数,因为你希望它返回一个斐波那契数,但你告诉我这与斐波那契数无关......?!您能否改写您的最后一句话,我觉得缺少“不”,因为这对我来说毫无意义。
            • 没有原始评论是正确的。您的回答似乎隐含地做出了错误的形而上学假设。我最初的问题显然是语义之一。
            • 所以你的问题是;我知道答案是正确的,但为什么它不是错误的答案,即为什么它有效?在这种情况下,我建议您学习使用调试器。 (通常在 IDE 上的“运行”按钮旁边)这将允许您逐步完成程序的每个阶段,查看值和结果,并帮助您不仅了解该程序的工作方式,还可以了解任何程序的工作方式。调试器是回答这个问题的最佳工具:为什么程序不做我认为应该做的事情。
            猜你喜欢
            • 2019-04-21
            • 2016-10-27
            • 1970-01-01
            • 2012-09-19
            • 2013-06-19
            • 2018-10-15
            • 2017-04-30
            • 2012-05-28
            • 1970-01-01
            相关资源
            最近更新 更多