| Name: _____________________ | Class: CET 375 |
| SSN/ID: _____________________ | Section & Group: ____________ |
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:
o, 8, 8o, 88o, 888oo, 88888ooo, 88888888ooooo, ...
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 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.
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.
| 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.
| Input | 9 | 10 | 15 | 20 | 25 | 30 | 35 |
| Result |
Hmm... we probably shouldn't try for the 50th or 100th Fibonacci numbers, should we?
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.
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 +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.F(6)2 → 3 ↓ ↑ F(6): return 1 +F(3)1 ↓ ↑ F(6): return 1 +F(1)0 ↓ ↑ F(1): return 0
| 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 |
|---|---|---|
|
|
x = RecFibonacci(4); // 1
| 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.
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 |
|---|---|---|
|
|
x = RecFibonacci(4); // 1
| 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.