开发者

C++ Recursion Issue

I feel a little dumb asking this, but here we go...

When trying to follow the Recursion example at the following website http://www.cplusplus.com/doc/tutorial/functions2/, I ran into a road b开发者_如何学Cump that has me perplexed.

I altered the code slightly just to get my head around the code in the recursion example and I pretty much have my head around it, but I can't figure out why the variable 'n' increments in 'Pass B' when I have not told the program to increment 'n'.

Could you please help explain this?

#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;
}


That's because you are unrolling the recursion.

You are not really incrementing n you are just returning to previous function call where n was n+1 before you called factorial(n-1) ...

When you start you go up to

   r = n * factorial (n-1);

which will cause another function call to the factorial.

You keep doing that (start from beginning of your function and go up to the call to factorial with n decremented by 1) until you eventually end up in a function call to factorial where n<=1.

In which case you return 1, but you return to previous call of factorial where n was 2, you do the multiplication (n * whatever was returned by factorial) and you finish the B path of that call and return r.

But you again return to the previous function call where you do the multiplication part and finish the B path and so on ...

factorial(5)
  factorial(4)
    factorial(3)
      factorial(2)
        factorial(1)
        return 1
      return r
    return r
  return r
return r


You see all "Pass A"-s in order and then all "Pass B"-s in reverse order which gives the impression that n increments eventhough you only see the originally passed n's.


It seems to me that your program works correctly and should output something like this for number=3 (Line breaks removed for readability):

Pass A n=3 r=0 [1]

Pass A n=2 r=0 [2]

Pass B n=2 r=2 [3]

Pass B n=3 r=6 [4]

So I think I can see how you would conclude that the n is incrementing in pass B but this in fact not the case. You need to keep in mind that n is a function local variable so in this case the n printed in [3] is a DIFFERENT instance of the local variable to the n in [4].

The values of n printed in [1] and [4] are from the top call of the function (where n=3), the values printed in [2] and [3] are the call in the top version of factor (i.e n-1).


If you notice, Pass B is not really passing through the function the second time, it only print the results of the recursion.

So A print 4, 3, 2, etc, while backwords B prints 4 3 2 1 (ie 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 . . .

Try replacing the second r prints as

   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 . . .


Pass B is printed when it is "unwinding" the recursion. It recursed until it hit the "else return (1);" part and then started backing out. Because it called itself with one less for n each time on the way in, it appears to be incrementing as it backs out.


The value of n in pass A and pass B will always be the same as you are not changing it anywhere in between. You pass n-1 to a recursive call but that does not change the value of n.

The reason why you might be confused is that you don't see pass A and pass B for a given n (n>2) next to each other.

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


Because that's when the recursion rewinds.

Maybe it would be easier to think about the case when n is 2. In that case you enter the conditional block and recurse after "Pass A". When you recurse n is 1, and so you return through the else block. When you return you are back at the previous frame of the recursion, where n is 2. r gets updated according to the result of the recursion call, 2*1, but n remains 2 as in the previous frame.

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

If n would be initially any larger value then you'd keep rewinding, and n would restore its value to each value it had prior to each recursion.

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


Some of the answers use indentation to make it easier to understand what's happening - you case use the same effect to make your own debug output more comprehensible: Try and change your function to something like this:

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...

My use of std::string may be a bit flaky, but you'll get the idea. Your output should now look like this.

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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜