理解递归和预递减

时间:2016-09-20 17:00:39

标签: c increment decrement

嗨,有人可以解释一下这段代码吗?

#include <stdio.h>

int main(){

    void myfunc(int x){
        printf ("  [%d]",x);
        printf ("M here 1\n");
        if (x > 0) myfunc(--x);
        printf ("M here 2\n");
        printf ("  %d,\n",x);
    }
    myfunc(5);
}

输出结果是:

[5]M here 1 
[4]M here 1 
[3]M here 1 
[2]M here 1 
[1]M here 1 
[0]M here 1 
0,M here 2   [0]
0,M here 2   [1]
1,M here 2   [2]
2,M here 2   [3]
3,M here 2   [4]
4,M here 2   [5]

然而,我被困在如何,

0,M here 2   [0]
0,M here 2   [1]
1,M here 2   [2]
2,M here 2   [3]
3,M here 2   [4]
4,M here 2   [5]

不应该停在

0,M here 2   [0]

2 个答案:

答案 0 :(得分:2)

  

不应该停在

不,不应该。递归调用返回后,函数继续执行该行之后的行。

当输入为myfunc时,让我们通过2的借口。之后,您可以将其推断为更高的值。使用2调用函数时,您会得到:

printf ("  [%d]",2);
printf ("M here 1\n");
myfunc(1);               // Since 2 > 0
printf ("M here 2\n");
printf ("  %d,\n",1);    // You get 1 here since x is decremented.

使用1调用该函数时,您将获得

printf ("  [%d]",1);
printf ("M here 1\n");
myfunc(0);               // Since 1 > 0
printf ("M here 2\n");
printf ("  %d,\n",0);    // You get 0 here since x is decremented.

使用0调用该函数时,您将获得

printf ("  [%d]",0);
printf ("M here 1\n");
// No more recursion since the input is 0
printf ("M here 2\n");
printf ("  %d,\n",0);    // You get 0 here since x is NOT decremented.

现在,如果你压缩递归调用,你会得到:

printf ("  [%d]",2);
printf ("M here 1\n");

   printf ("  [%d]",1);
   printf ("M here 1\n");

      printf ("  [%d]",0);
      printf ("M here 1\n");
      printf ("M here 2\n");
      printf ("  %d,\n",0);

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

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

很容易理解为什么会产生输出:

  [2]M here 1
  [1]M here 1
  [0]M here 1
M here 2
  0,
M here 2
  0,
M here 2
  1,

答案 1 :(得分:1)

这是你的代码,我只更改了传递给main函数中myfunc的参数并标记了不同的行,因此更容易解释会发生什么:

#include <stdio.h>

int main(){

  void myfunc(int x){
    printf ("  [%d]",x);      // [1]
    printf ("M here 1\n");    // [2]
    if (x > 0)                // [3]
      myfunc(--x);            // [4]
    printf ("M here 2\n");    // [5]
    printf ("  %d,\n",x);     // [6]
  }

  myfunc(2);                  // [7]
}

以下是发生的事情。在执行代码行的第一列中,在中间列中,执行它的上下文,在最后一列中,在当前上下文中x的值。

                                Context               Value of x

[7] Call myfunc(2)              Main function         N/A
|                              
+-> [1] print                   1st call to myfunc    2
    [2] print                   1st call              2
    [3] x > 0 is true           1st call              2
    [4] x := x - 1              1st call              1
    [4] Call myfunc(x)          1st call              1
    |                          
    +-> [1] print               2nd call to myfunc    1
        [2] print               2nd call              1
        [3] x > 0 is true       2nd call              1
        [4] x := x - 1          2nd call              0
        [4] Call myfunc(x)      2nd call              0
        |
        +-> [1] print           3rd call to myfunc    0
            [2] print           3rd call              0
            [3] x > 0 is false  3rd call              0
            [5] print           3rd call              0
            [6] print           3rd call              0
            Retun               3rd call              0
            |
          <-+
        [5] print               2nd call to myfunc    0
        [6] print               2nd call              0
        Retun                   2nd call              0
        |
      <-+
    [5] print                   1st call to myfunc    1
    [6] print                   1st call              1
    Return                      1st call

如果您使用相应的x值调用所有调用的打印件,则会得到:

[1] print 2        
[2] print 2        >   [2]M here 1
[1] print 1        
[2] print 1        >   [1]M here 1
[1] print 0        
[2] print 0        >   [0]M here 1
[5] print 0        > M here 2
[6] print 0        >   0,
[5] print 0        > M here 2
[6] print 0        >   0,
[5] print 1        > M here 2
[6] print 1        >   1,

在重复发生时,您必须记住,每次在内部调用函数时,在某个时刻,此调用将返回,并且以下语句将正常执行。构建/理解递归函数的一个好方法是看它不是一组“独立”处理的语句,而是将它看作是完成某项工作的整个指令。这样,如果您可以首先编写函数的规范,那么您就知道如何在其自身内部重用它以及它是否安全。