递归混淆

时间:2015-02-25 09:13:36

标签: c function recursion

大家好,我很难理解递归函数调用,当我认为我理解它们时,我看到一个让我意识到我错了的问题 我无法理解程序的流程

#include <stdio.h>
void fun(int n)
{   
    if(n>0)
    {   
        fun(--n);
        printf("%d\n",n);
        fun(--n);
    }
}   
int main(void) {
    int a;
    a=3;
    fun(a);
    return 0;
}

8 个答案:

答案 0 :(得分:2)

当n = 3

时,这是函数的函数调用
f(3)
.f(2) [1]
..f(1) [1]
...f(0) [1]
...Print 0
...f(-1) [2]
..Print 1
..f(0) [2]
.Print 2
.f(1) [2]
..f(0) [1]
..Print 0
..f(-1)[2]

其中.表示堆栈的深度,1和2指定它是从循环中的第一次递归调用还是第二次。

由于

f(3)

变为

f(2)
print 2
f(1)

其中的内容变为

f(1)
print 1
f(0)
print 2
f(0)
print 0
f(-1)

最终成为

f(0)
print 0
f(-1)
print 1
f(0)
print 2
f(0)
print 0
f(-1)

f(n)

时删除所有n <= 0
print 0
print 1
print 2
print 0

答案 1 :(得分:1)

我认为混淆的原因是你假设同样的&#34; n&#34;每次调用函数fun()时都会使用它。事实上,情况并非如此,因为在C语言中,参数是按值传递的。也就是说,当fun(3)调用fun(2)时,会创建一个新的n - 特定于fun(2)的一个实例。因此,在fun(3)内调用fun(2)后,n的值为2,而不是-1。

你应该期待......

有趣(1)打印0
有趣(2)打印1
有趣(3)打印2
fun(1)(从第二次调用fun(2)调用)打印0

那就是它。

答案 2 :(得分:1)

让我们尝试用案例n=2来理解它,然后你应该能够概括。

fun (2):

内部发生了什么(流程):

1)n=2: if(n>0)为真,fun(--n)被调用,n设置为值1,原因是 - ; (见下面的步骤)。

2)n=1:现在n=1:再次if(n>0)为真,fun(--n)n=0一起调用。见下面的步骤。

3)n=0:现在n=0; if(n>0)是假的,所以我们回来了。

我认为这是你的困惑。从第3步开始,将被抛回第2步不是第1步)。在fun(--n)调用后,您实际上在步骤2中被抛出 - 因此,printf的值为n=0,因为减少而被调用。 然后再次在同一个地方(printf之后)fun(--n)被调用值n=-1但是,它也会退出 - 最终你将被抛出开头。

答案 3 :(得分:1)

我会画一个&#34;呼叫树&#34;帮助可视化该计划。

该功能有那些部分

decrement n, call, print, decrement n, call

现在你可以画出这个:

                  0                 -1
            1->0,   print 0, 0->-1,                   0
      2->1,                            print 1, 1->0,                 1->0, .....
3->2,                                                   print 2, 2->1, .....

从左下角开始,每次通话都上一行。程序从左到右执行,您可以清楚地看到打印数字的顺序。

答案 4 :(得分:1)

以下是发生的事情(伪代码):

   n = 3
   fun(3);
      n = 2
      fun(2); // first fun(--n)
         n = 1
         fun(1); // first fun(--n)
            n = 0
            fun(0); // first fun(--n)
               return;
            print 0
            n = -1
            fun(-1); // second fun(--n)
               return;
            return;
         print 1
         n = 0
         fun(0); // second fun(--n)
            return;
         return;
      print 2
      n = 1
      fun(1); // second fun(--n)
         n = 0
         fun(0); // first fun(--n)
            return;
         print 0
         n = -1
         fun(-1); // second fun(--n)
            return;
         return;
      return;
   return;

答案 5 :(得分:0)

通过迭代扩展函数调用和删除条件,可以理解程序的输出;以伪代码的方式,这可以如下完成。

fun(3)

可以扩展到以下内容。

if(3>0)
{   
    fun(2);
    printf("%d\n",2);
    fun(1);
}

在以下步骤中,如果if条件评估为false,则省略{。}}条件。

fun(1);
printf("%d\n",1);
fun(0);
printf("%d\n",2);
fun(0);
printf("%d\n",0);
fun(-1);

可以省略对具有非正参数的fun的调用,因为它们不会生成任何输出。

fun(1);
printf("%d\n",1);
printf("%d\n",2);
printf("%d\n",0);

进一步扩展产生以下顺序。

fun(0);
printf("%d\n",0);
fun(-1);
printf("%d\n",1);
printf("%d\n",2);
printf("%d\n",0);

这可以再次简化为以下顺序。

printf("%d\n",0);
printf("%d\n",1);
printf("%d\n",2);
printf("%d\n",0);

总的来说,输出结果如下。

0
1
2
0

我希望这能回答你的问题;但是,它没有提供描述生成输出的直观方式。

答案 6 :(得分:0)

要了解递归流程,您可以使用如下所示的少量printfs来检测代码。这将显示使用缩进的函数流程序列。

#include <stdio.h>

void printSpace(int num)
{
    while(num > 0)
    {
        printf(" ");
        num--;
    }
}

int NumSpace = 0;
void fun(int n)
{   
    printSpace(NumSpace);
    printf("fun(%d)\n", n);
    NumSpace += 4;
    if(n>0)
    {   
        fun(--n);
        printSpace(NumSpace);
        printf("%d\n",n);
        fun(--n);
    }
    NumSpace -= 4;
}   
int main(void) {
    int a;
    a=3;
    fun(a);
    return 0;
}


Result:
fun(3)
    fun(2)
        fun(1)
            fun(0)
            0
            fun(-1)
        1
        fun(0)
    2
    fun(1)
        fun(0)
        0
        fun(-1) 

希望这有帮助。

答案 7 :(得分:0)

尽可能避免使用递归代码。正如您通过这个简单的示例所看到的,理解程序的流程可能很难。想象一下,在一个非常复杂的代码中找到错误是什么感觉。 对于那些认为值得投票的人来说......在用C编码的20年中,我发现很少有真正需要它的场合。