Methods 递归-一条语句中的两个调用

Methods 递归-一条语句中的两个调用,methods,recursion,call,Methods,Recursion,Call,我试图理解下面代码片段中的递归调用 static long fib(int n) { return n <= 1 ? n : fib(n-1) + fib(n-2); } 静态长fib(int n){ 返回n Java和C&sharp; 子表达式按从左到右的顺序求值。fib(n-1)在fib(n-2)之前求值。请参阅 需要注意的是,这里的评估顺序并不重要,因为fib()没有任何副作用 C与C++ 这两个函数以不确定的顺序调用,一旦调用了这两个函数,它们的返回值就会相加并返回。您不

我试图理解下面代码片段中的递归调用

static long fib(int n) {
    return n <= 1 ? n : fib(n-1) + fib(n-2);
}
静态长fib(int n){
返回n Java和C&sharp;
子表达式按从左到右的顺序求值。
fib(n-1)
fib(n-2)
之前求值。请参阅

需要注意的是,这里的评估顺序并不重要,因为
fib()
没有任何副作用

C与C++ 这两个函数以不确定的顺序调用,一旦调用了这两个函数,它们的返回值就会相加并返回。您不知道,可以先调用左函数,也可以先调用右函数

这似乎有问题,但事实并非如此,因为调用顺序无关紧要。调用
fib(i)
没有任何副作用(例如修改其他变量、打印消息等),因此两个函数调用完全独立

一个编译器可能决定先计算左侧,再计算右侧:

 1. f(3)
 2.   f(2)
 3.     f(1)
 4.       return 1
 5.     f(0)
 6.       return 0
 7.     return 1 + 0
 8.   f(1)
 9.     return 1
10.  return 1 + 1
另一个可能会决定先评估右侧,再评估左侧:

 1. f(3)
 2.   f(1)
 3.     return 1
 4.   f(2)
 5.     f(0)
 6.       return 0
 7.     f(1)
 8.       return 1
 9.     return 1 + 0
10.  return 1 + 1
Gcc-S纤维c:

    subl    $1, %eax
    movl    %eax, (%esp)
    call    _fib
    movl    %eax, %ebx
    movl    8(%ebp), %eax
    subl    $2, %eax
    movl    %eax, (%esp)
    call    _fib
那么,首先调用左边的一个。然后呢?它也为(n-2)调用fib,没有 知道正确的分支也在计算相同的事情


这个众所周知的例子的复杂性为O(n^2),这意味着如果n=10,它会使用不同的参数调用self~100次,即使10次已经足够了。

首先调用哪个函数并不重要。此函数返回斐波那契序列中的第n个数,通常可以通过将前两个数相加来找到该数(特殊情况下,序列中的前两个为0和1)

所以这个函数计算fib(n)的作用是求fib(n-1)和fib*(n-2)并将它们相加得到fib(n)。当然,fib(n-1)通过求fib(n-2)和fib(n-3)来工作,而fib(n-2)通过求fib(n-3)和fib(n-4)来工作,依此类推,直到序列的最开始(0和1)由于这些函数可以在没有任何进一步递归的情况下返回,因此递归结束,每个打开的函数返回到调用它的函数,一直返回到链的后面


有一种更有效的方法可以做到这一点,它不需要两个单独的递归,但看起来不会那么优雅。

可能没有定义
+
操作符的求值顺序(它依赖于实现),意思是:要么
fib(n-1)
要么
fib(n-2)
可以先执行。无论哪种方式,结果都是相同的,在这种特殊情况下,这并不重要:两个递归调用将在返回之前计算并相加,从调用位置,您只会看到求和的最终结果。

为了理解这一点,我使用了下面的代码,并且输出消除了所有疑问:(C#)

输出: 5. 2. 50 四,


简而言之,它将完成左表达式的递归,然后向右移动。

您可以尝试打印n的值,然后自己查找。@DavidBejar“试试看”并不总是好建议,尤其是在行为可能是实现定义的或未定义的情况下(
i=i++
)。如果你只想知道函数调用的顺序,这是没有帮助的,但是《计算机程序的结构和解释》这本非常流行的教科书,在中对这种算法有很好的可视化效果。@JohnKugelman“试试看”在处理递归时,这是一个特别危险的建议,如果您出错,函数可能永远不会返回;)嗯……如果这是‘不确定顺序’的情况,我们如何预测答案?我想,如果它完全独立,那么我们就不会得到想要的答案。假设n是10,那么我们期望方程是9+8。如果第一个先被调用,结果是9,假设第一个再次被调用,那么n是8,然后调用第二个,结果是8,所以我们得到8+8,这不是我们想要的。也许我没有正确理解你的答案?你没有理解,凯文。fib(n-1)和fib(n-2)的顺序无关紧要,因为a)都必须在表达式
fib(n-1)+fib(n-2)之前求值
可以进行评估,b)这两个调用是完全独立的,它们的结果并不相互依赖。fib(n-1)将始终可靠地为n,fib(n-2)的任何一个值返回一个值将始终返回另一个特定值,并且将这两个值相加将始终为n的任何一个值提供相同的结果。Kevin,只需假设fib是一个可靠的函数,并且始终为fib(n)返回正确的值。因此,fib(6)返回5(这是系列中的第6个元素),而fib(7)返回8(第7位)。现在,假设调用fib(8)。fib函数试图通过将fib(6)和fib(7)相加来计算它。它是第一次还是第二次计算fib(6)有什么关系?它仍然将答案与8相加,得到13。
        static void Main(string[] args)
    {
        var data = series(5);
        Console.WriteLine(data);
    }

    public static int series(int n)
    {
        Console.WriteLine(n);
        if (n ==2)
        {
            return 1;
        }
        if (n == 50)
        {
            return 3;
        }
        else
        {
            return series(2) + series(50);
        }
    }