我无法理解这个Fibonacci程序流程

时间:2017-09-18 07:23:32

标签: c#

所以我对编程和思想世界不熟悉我拿起一本书来开始学习。我买了C#3rd Edition的玩家指南和它给你的一个小作业,让我很难过。我一步一步地调试它以帮助我理解,但程序的流程对我来说毫无意义。在这里。

      static void Main(string[] args)
        {
            for (int index = 1; index <= 10; index++)
            {
                Console.WriteLine(Fibonacci(index));
            }

            Console.ReadKey();
        }

        /// <summary>
        /// Returns a number from the Fibonacci sequence, starting at 1.
        /// Note that this implementation is not very optimized, and can
        /// take a very long time if you're looking up large numbers.
        /// </summary>
        /// <param name="number"></param>
        /// <returns></returns>
        static ulong Fibonacci(int number)
        {
            if (number == 1) { return 1; }
            if (number == 2) { return 1; }

            return Fibonacci(number - 1) + Fibonacci(number - 2);
        }

前两次它通过for循环打印出来&#39; 1&#39;和&#39; 1&#39;因为第一次通过索引是&#39; 1&#39;使第一个if语句为真,第二次通过索引是&#39; 2&#39;使第二个if语句成立。但是当它第三次运行并且索引转到3时它转到那个return语句,如果我的数学是正确的(3-1)+(3-2)等于3,这是正确的。所以我希望它从方法返回3中断并将其写入控制台窗口,但它没有。相反,这次再次通过该方法说这个数字的值是2.(好吧??)至少它应该停在第二个if语句并重新打印&#39; 1&#39;再次。不,它忽略了该行再次击中return语句。这到底是怎么回事?请解释一下这个逻辑。

2 个答案:

答案 0 :(得分:8)

这种递归的地狱有很好的例证。

请注意,插图适用于循环的一次迭代

此外,它是为此代码绘制的:

return Fibonacci(number - 2) + Fibonacci(number - 1);

如果你有相反的添加,正确的程序流程将与下图所示的相反。

fibonacci recursive calls

图片来自:http://composingprograms.com/pages/28-efficiency.html

我称它为地狱有两个原因:

难以阅读开发者

第一次使用参数6调用fib函数时,它首先调用fib(4),(树的左侧部分),然后,当它结束时,调用fib(5)(正确的树的一部分)。

然而,对于某些情况,递归可能非常有用,但是这个学校一个绝对不适合这种递归。代码的目的不是只由编译器读取,也应由开发人员阅读。

低效

正如您所看到的,一些fib(n)被称为具有相同n的几次。

最后,这个递归算法is O(2^n),这个问题非常糟糕

循环中效率更低

请记住,插图仅适用于一次迭代!您可以为每个n绘制fib(n)的图表。

使用此方法,您将丢失先前计算的每个值,而不是重复使用它们来计算下一个值。该循环具有复杂度O(n * 2 ^ n)

答案 1 :(得分:3)

嗯,这不是一个简单的递归示例,并且最糟糕的是,它在循环中被执行......我几乎不会用什么来教人们递归是什么。

因此,递归的一点是,一个函数会一遍又一遍地执行,直到它的停止条件得到满足(如果它永远不会满足或者甚至不存在,它将会创造一个无限的递归,大多数时候都不是一件好事。)

递归的典型例子是计算阶乘(如果你不记得它是如何工作的,5!= 5 * 4 * 3 * 2 * 1)。

因此,阶乘递归方法的实现将是这样的:

Int64 Factorial(int input)
{
    if(input < 0) 
    {
         throw new ArgumentOutOfRangeException("Input must be 0 or higher.");
    }
    if(input < 2) 
    {
        return 1;
    }
    return input * Factorial(input - 1);
}

(0!= 1,-3!无效......)

现在,我们假设你用数字3来称呼这个方法:
Factorial(3)将返回3 * Factorial(3-1) 同样,Factorial(2)将返回2 * Factorial(2-1) Factorial(1)只会返回1 将所有内容Factorial(3)放在一起将返回3 * 2 * 1 3!

现在,在您的情况下,Fibonacci递归方法停止条件的数字是1或2,但它自己调用两次:Fibonacci(number - 1) + Fibonacci(number - 2);。最糟糕的是,它从for循环中执行,通过索引(从1到10)计算Fibonacci序列上的数字。

让我们来看看Fibonacci(3)做了什么:

Fibonacci(3)将返回Fibonacci(3-1) + Fibonacci(3-2) Fibonacci(2)将返回1 Fibonacci(1)将返回1

因此,Fibonacci(3)将返回1 + 1。

让我们采取下一个数字:

Fibonacci(4)将返回Fibonacci(4-1) + Fibonacci(4-2) 我们已经计算出Fibonacci(3)返回2,我们知道Fibonacci(2)将返回1,因此Fibonacci(4)将返回3 (如果你想进入每一个电话,或者1 + 1 + 1)。

同样,Fibonacci(5)将返回Fibonacci(5-1) + Fibonacci(5-2) - 所以它是3 + 2,依此类推(Fibonacci(6)将返回5 + 3,{{ 1}}将返回8 + 5)。