Name: _____________________ Class: CET 375
SSN/ID:   _____________________ Section & Group: ____________
Recursion


A. Review of Recursion

It is sometimes convenient to write functions that call themselves. This phenomenon is known as recursion and is most useful when working with problems that have a recursive structure. Sections 7.1 - 7.3 of the text C++: An Introduction to Data Structures contain examples of several such problems and examples of recursive functions.

The Fibonacci sequence has such a structure. It is so named because it arose in a problem solved by Leonardo de Pisa (whose nickname was Fibonacci). This problem involves the proliferation of rabbits living in a closed colony:

A pair of rabbits must mature two months before it can produce young and then produces one new pair each month thereafter. Starting with one pair, how many pairs will be there after any given month?
If o denotes a young pair and 8 a mature pair, the first few generations are:

    o, 8, 8o, 88o, 888oo, 88888ooo, 88888888ooooo, ...
    
Clearly, the Fibonacci sequence, which is the number of pairs of rabbits at each generation,

     1, 1, 2, 3, 5, 8, 13, 21, ...
begins with two 1s and each number thereafter is the sum of the two preceding integers.

  1. What are the next 4 numbers in this Fibonacci sequence?




    The definition of the sequence can be written recursively as follows:
    
             {1 if n = 1
    fib(n) = {1 if n = 2
             {fib(n - 2) + fib(n - 1) if n > 2
        
    Note that this definition follows the basic pattern for recursive definitions in which there are two parts:

    As an example, fib(1) gives the value of the first element of Fibonacci sequence, 1, and fib(2) gives the value of the second element in the sequence, 1. The definition can also be expanded recursively, as in:

    
    fib(3) = fib(1) + fib(2)
            = 1 + 1
            = 2
        
    In this expansion, we started with fib(3), which, according to the definition, is equal to fib(3-2) + fib(3-1). After this, we can use the values provided for fib(1) and fib(2) in the base cases.
  2. Recursively expand the definition for fib(4) in a similar manner, applying the definition repeatedly until you reach a base case.
  3. When writing recursive functions, you need to remember three key things:
    1. You must code the base case(s).
    2. You must code the inductive case(s).
    3. You must ensure that the recursive calls make progress toward the base case(s).

    You must, therefore, write an algorithm that looks something like:

    
    if (base-case(s))
       return certain specified value(s)
    else
       make the recursive call(s) to the function
        
    In the space below, write an algorithm for a recursive version of the Fibonacci function.














    Notes: In what follows, you will use the program rectester.cpp to test your recursive function. Get a copy of this program by right-clicking and saving the following link: source_lab09_rectester.cpp and then rename the file to rectester.cpp.
  4. In the space indicated in rectester.cpp, write a recursive function (to be called RecFibonacci) that implements your algorithm. Compile and execute the program with the base cases (i.e., 1 or 2) only. What does the function return for these cases?






    If there are any problems, fix them first. The base cases should be the easiest because they require no recursive calls.
  5. To test the recursive part of the code, execute the program with inputs 3, 4, 5, 6, 7 and record your results:

    Input 3 4 5 6 7
    Result                              

    Does your recursive routine return the same values as given on the preceding page? If not, fix it up before going on.

  6. When you're convinced that your function is working correctly, execute the program with the following inputs and record the output here:

    Input 9 10 15 20 25 30 35
    Result                                          

    Hmm... we probably shouldn't try for the 50th or 100th Fibonacci numbers, should we?

  7. What would happen if you removed the base cases from RecFibonacci()?






Tracing Recursive Functions — Version 1

Learning how to write and use recursive functions can be difficult for beginning programmers. Tracing step by step how a recursive function executes is helpful in understanding how the function works and is also a useful tool for debugging the function. In this lab, we will do hand tracing; in another lab, we might do machine tracing.

  1. Consider the function shown below:
    
    int F(int n) {
      if (n < 2)            // 2
        return 0;           // 3
      // else
        return 1 + F(n/2);  // 4
    }
        
    Suppose this function is called by:
    
    x = F(4);       // 1
        
    You can picture it something like this for F(12):
    F(12):  return   1   +  F(6)  2   →   3
      ↓                     ↑
    F(6):   return   1   +  F(3)  1
      ↓                     ↑
    F(6):   return   1   +  F(1)  0
      ↓                     ↑
    F(1):   return   0           
        
    The following table traces the execution of this function call. The indentation and alignment of the function calls in the right column is intended to show how deep we are into the recursion and which function call we are currently dealing with.

    Statements Being Executed Action Current Function Call
    1 Call function F with argument 4
    F(4)
    2,4 Inductive Step: Call F with argument 4 / 2 = 2
       F(2)
    2,4 Inductive Step: Call F with argument 2 / 2 = 1
          F(1)
    2,3 Anchor: Return value 0 to previous function call
    4 Calculate 1 + 0 = 1 and return this to the previous function call
       F(2)
    4 Calculate 1 + 1 = 2 and return this to the previous function call
    F(4)
    1 Assign 2 to x

    Make a trace table like that above for the statement

    x = F(6);   //1
    Statements Being Executed Action Current Function Call
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	  

  2. In your function, RecFibonacci(), use commented "statement numbers" (starting with 2) like those in the function F() to number the instructions and then make a trace table like those on the preceding page for the function call:
    
        x = RecFibonacci(4);     // 1
        
    Note: You may abbreviate the function name to RF to save some writing.

    Statements Being Executed Action Current Function Call
    1 Call function RF with argument 6
    RF(6)
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	  

Tracing Recursive Functions — Version 2

Next, let's trace step by step how a recursive function is implemented using a run-time stack as described in Section 7.3 of the text C++: An Introduction to Data Structures. This can prove very helpful in understanding how the function works and is also a useful tool for debugging the function. In this lab, we will do hand tracing; in another lab, we might do machine tracing.

  1. Consider the function shown below:
    
    int F(int n) {
      if (n < 2)            // 2
        return 0;           // 3
      // else
        return 1 + F(n/2);  // 4
    }
        
    Suppose this function is called by:
    
    x = F(4);       // 1
        
    You can picture a Fibonacci tree as follows:
    
                6 
               /\
              5 →
             /
            4 →
           /
          3 →
         /\
        2  1
        
    And you can picture the above sequence for F(4) as follows:
    
               F(4) 
               / \
              1 + F(2)
                  / \
                 1 + F(1)
                       \
                        0 
        
    The following table traces the execution of this function call; each activation record (a.r.) consists of:

    parameter n value returned by F return address [the numbers following //]

    Function Call Run-Time Stack Action
    ___________ (empty)
    F(4)
    |4|?|1| Push a.r. onto stack
       F(2)
    |2|?|4|
    |4|?|1|
    Push a.r. onto stack
          F(1)
    |1|?|4|
    |2|?|4|
    |4|?|1|
    Push a.r. onto stack
    |2|?|4|
    |4|?|1|
    Calculate 0 for F(1), pop a.r. |1|0|4| from stack, and return to instruction 4
    |4|?|1| Calculate 1 + 0 = 1 for F(2), pop a.r. |2|1|4| from stack, and return to instruction 4
    ___________ (empty) Calculate 1 + 1 = 2 for F(4), pop a.r. |4|2|1| from stack, return to instruction 1, and assign 2 to x

    Make a trace table like that above for the statement

    x = F(6);   //1
    Function Call Run-Time Stack Action
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	  

  2. In your function, RecFibonacci(), use commented "statement numbers" (starting with 2) like those in the function F() to number the instructions and then make a trace table like those on the preceding page for the function call:
    
        x = RecFibonacci(4);     // 1
        
    Note: You may abbreviate the function name to RF to save some writing.

    Function Call Run-Time Stack Action
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	                                           
    	  

Hand In this lab handout with the answers filled in and attach a printout containing a listing of the final version of rectester.cpp and one sample run with input 30. You may use the enscript command from your Programming Style Sheet:
enscript -E -G -2rj -M Letter -PECT2_PS rectester.cpp. Or, you may use the a2ps command: a2ps rectester.cpp.


Ricky J. Sethi <rickys at sethi.org>
Last modified: Mon Mar 28 18:35:15 PST 2005