为什么这种递归用作返回值?

时间:2019-06-24 20:17:49

标签: c recursion

我们使用值n进行递归。我们将此值保存在变量x中。然后,变量x被作为返回值添加到递归中。究竟如何运作?

我尝试了不同的方法来检查您是否首先对x使用递归,然后再使用x将其添加到另一个递归中。

#include <stdio.h>
#include <stdlib.h>

int up(int n)
{
    int x;

    if(n == 0)
    {
        return 0;
    }
    else if(n == 1)
    {
        return 1;
    }
    else
    {
        x = up(n - 2);
        return x + up(n - 1);
    }
}

int main(void)
{
     int n = 20;
     int res;
     res = up(n);
     printf("Result %d\n", res);
     return 0;
}

结果是6765。由于这是学校提供的代码,因此结果应该不错。我只是不明白为什么。

3 个答案:

答案 0 :(得分:0)

听起来您在递归地把握函数作用域的概念时遇到了问题。通常,将递归视为树/堆栈最容易。

堆栈:

对于一个简单的例子,假设n = 5。 Up(5)被推入堆栈。 然后,您声明此函数范围内的x是UP(3)。 现在将UP(3)压入堆栈,并且UP(5)等待Up(3)返回。 堆叠顺序: Up(3) Up(5)

现在,Up(3)在此函数内部声明x为UP(1),并耐心等待Up(1)返回。由于x是在函数内部声明的,因此它们是局部变量,只能在声明它们的函数内部访问。这意味着Up(3)内部的X与Up(5)内部的X存储在内存中完全不同的位置。当您研究地址空间以及如何存储局部变量等时,您肯定会对此有所了解。但是继续前进!

堆栈: Up(1) Up(3) Up(5) Up(1)返回1,因此我们将其弹出堆栈!这意味着Up(3)可以继续运行。 堆叠: Up(3) Up(5) Up(3)现在具有x = 1(Up(1)的返回,并希望返回x + Up(2)。为此,我们将Up(2)推入堆栈。

堆栈: Up(2) Up(3) Up(5)

继续此示例,Up(2)将Up(0)添加到堆栈中。 Up(0)将返回0,因此Up(2)范围内的x设置为0。然后Up(2)将Up(1)添加到堆栈中,并返回1。Up(2)将返回(0 + 1)。现在我们可以通过从堆栈弹出Up(2)回到Up(3)。 Up(3)的x = 1,并希望返回(1 + 1)。从堆栈弹出Up(3),然后在堆栈上留下Up(5)。由于返回了Up(3),X现在设置为2。现在我们将Up(4)添加到堆栈中,该堆栈按此顺序添加Up(2),Up(0),Up(1),Up(3),Up(2),Up(0),Up(1)注意(在添加新呼叫之前,其中许多呼叫会弹出。)

我建议阅读有关全局范围和功能范围的内容。理解这些概念对于理解递归的基础至关重要。但是,您已经可以看到这种类型的递归是蛮力的,根本没有优化。例如,对于创建的每个递归调用,您要多次计算Up(2)。使用较大的数字时,这会导致可伸缩性问题,因为您要对同一数字重复多次相同的操作。可以通过一个记忆数组和一个较小的Big O运行时更多的逻辑来解决此问题,但是对于这个问题来说,可能在细节上太过复杂了。

答案 1 :(得分:0)

参数绑定对于每个调用都是唯一的。这意味着n中的up(20)不会与n中的up(19)混合。由于它不是参考,因此n - 1会作为新值进行计算并作为新值传递到旧的位置,因此在返回旧的n时,它就是附加调用期间的状态。局部变量也仅存在于作用域中,因此每个x也不同。

由于此函数是纯函数,因此它的结果是算法和参数的唯一乘积,我认为您应该从基本情况开始……

基本案例:

up(0) => 0
up(1) => 1

默认情况:

up(2) => up(2-2) + up(2-1) => up(0) + up(1) => 0 + 1 

现在我从那里的基本情况中知道了01的结果,您可以将其替换为结果。我们可以走得更远:

up(3) => up(3-2) + up(3-1) => 1 + 1 => 2
up(4) => up(4-2) + up(4-1) => 1 + 2 => 3
up(5) => up(5-2) + up(5-1) => 2 + 3 => 5
...

这个(斐波那契)序列的有趣之处在于,如果您拥有前两个数字,则可以生成下一个。这使得该序列成为尾递归或迭代循环的极佳候选者,两者均远优于易于阅读的递归版本。

答案 2 :(得分:0)

以下是该功能可以简化多少:

int Fib(int n)
{
    return (n<2 ? n : Fib(n-1) + Fib(n-2));
}

这是简单的C,而不是C ++