C ++递归问题

时间:2010-04-26 07:36:41

标签: c++ recursion

我觉得这有点愚蠢,但我们走了......

在尝试按照以下网站http://www.cplusplus.com/doc/tutorial/functions2/的递归示例时,我遇到了让我感到困惑的路障。

我稍微修改了代码只是为了让我的头围绕递归示例中的代码而且我几乎要理解它,但我无法弄清楚为什么变量'n'在'Pass B'中增加我没有告诉程序增加'n'。

你能帮忙解释一下吗?

#include <stdlib.h>
#include <iostream>

using namespace std;

long factorial (long n)
{
  if (n > 1)
{
   long r(0);
   cout << "Pass A" << endl;
   cout << "n = " << n << endl;
   cout << "r = " << r << endl;

   r = n * factorial (n-1);

   cout << "Pass B" << endl;  
   cout << "n = " << n << endl;
   cout << "r = " << r << endl;
   return (r);
}
  else
   return (1);
}

int main ()
{
  long number;
  cout << "Please type a number: ";
  cin >> number;
  cout << number << "! = " << factorial (number) << endl;
  system ("pause");
  return 0;
}

8 个答案:

答案 0 :(得分:3)

那是因为你unrolling是递归。

在您致电n之前,您刚刚回复nn+1factorial(n-1)的函数调用{/ 1}}

当你开始时,你去

   r = n * factorial (n-1);

将导致另一个函数调用factorial

你一直这样做(从你的函数开始,然后调用factorialn递减1)直到你最终结束对{{1}的函数调用} factorial

在这种情况下你返回1,但是你回到之前的n<=1为2的阶乘调用,你进行乘法运算(n)并完成n * whatever was returned by factorial的路径致电并返回B

但是你再次返回上一个函数调用,在那里你进行乘法部分并完成r路径,依此类推......

B

答案 1 :(得分:0)

您按顺序看到所有“通过A” - 然后按相反的顺序看到所有“通行证B” - 这给人的印象是,如果您只看到最初传递的n,则增加n。

答案 2 :(得分:0)

在我看来,你的程序工作正常,并且应该为number = 3输出这样的东西(为了便于阅读,删除了换行符):

通过A n = 3 r = 0 [1]

通过A n = 2 r = 0 [2]

通过B n = 2 r = 2 [3]

通过B n = 3 r = 6 [4]

所以我想我可以看到你如何得出结论n在传球B中递增但事实并非如此。 你需要记住,n是一个函数局部变量,因此在这种情况下,[3]中打印的n是[4]中n的局部变量的不同实例。

[1]和[4]中打印的n值来自函数的最高调用(其中n = 3),[2]和[3]中打印的值是最高版本中的调用因子(即n-1)。

答案 3 :(得分:0)

如果你注意到,Pass B第二次没有真正通过该函数,它只打印递归的结果。

所以A打印4,3,2等,而背面B打印4 3 2 1(即2 3 4)

Please type a number: 4
Pass A
n = 4
r = 0
Pass A
n = 3
r = 0
Pass A
n = 2
r = 0
Pass B
n = 2
r = 2
Pass B
n = 3
r = 6
Pass B
n = 4
r = 24
4! = 24
Press any key to continue . . .

尝试将第二个r打印替换为

   cout << "Pass B" << endl;  
   cout << "n = " << n << endl;
   cout << "r = " << r << " --- NOTICE RESULT ACCUMULATING AS WE UNNEST THE RECURSION" <<endl;

PS C:\temp> .\r.exe 4
Please type a number: 4
Pass A
n = 4
r = 0
Pass A
n = 3
r = 0
Pass A
n = 2
r = 0
Pass B
n = 2
r = 2 --- NOTICE RESULT ACCUMULATING
Pass B
n = 3
r = 6 --- NOTICE RESULT ACCUMULATING
Pass B
n = 4
r = 24 --- NOTICE RESULT ACCUMULATING
4! = 24
Press any key to continue . . .

答案 4 :(得分:0)

在“展开”递归时打印通行证B.它一直递响,直到它击中“else return(1);”部分然后开始退出。因为在每次进入的过程中它都会用n减去n,所以当它退出时它似乎在递增。

答案 5 :(得分:0)

传递n和传递AB的值始终相同,因为您不会在其间的任何位置更改它。您将n-1传递给递归调用但不会更改n的值。

您可能会感到困惑的原因是您没有看到通过A并将B传递给彼此相邻的n (n>2)

When n=2, you'll see:
pass A for n=2
pass B for n=2

When n=3, you'll see:
pass A for n=3
pass A for n=2 // cuz of recursive call.
pass B for n=2
pass B for n=3 // looks like n has increment here..but this 'pass B' pairs with first pass A

答案 6 :(得分:0)

因为那是递归倒带的时候。

n为2时,可能会更容易思考这种情况。在这种情况下,您输入条件块并在“Pass A”之后递归。当您递归n为1时,您将返回else块。当你返回时,你回到了递归的前一帧,其中n是2. r根据递归调用的结果2*1得到更新,但n与前一帧中一样保持2

factorial(2)
  factorial(1)
factorial(2)

如果n最初会有更大的值,那么你将继续倒带,n会将其值恢复为每次递归之前的每个值。

factorial(3)
  factorial(2)
    factorial(1)  // returns 1
  factorial(2)    // r=2*1
factorial(3)      // r=3*2

答案 7 :(得分:0)

有些答案使用缩进来更容易理解正在发生的事情 - 您使用相同的效果来使您自己的调试输出更易于理解: 尝试将您的功能更改为以下内容:

long factorial (long n, std::string prefix= "") // default parameter
  ...
   cout prefix << "Pass A" << endl;
   cout prefix << "n = " << n << endl;
   cout prefix << "r = " << r << endl;

   r = n * factorial (n-1, prefix+ "  "); // increase indentation
   ...etc...

我对std :: string的使用可能有点不稳定,但你会明白这一点。您的输出现在应该是这样的。

Please type a number: 4

Pass A
n = 4
r = 0
  Pass A
  n = 3
  r = 0
    Pass A
    n = 2
    r = 0
    Pass B
    n = 2
    r = 2
  Pass B
  n = 3
  r = 6
Pass B
n = 4
r = 24

4! = 24