n F(n) 1 1 2 1 3 2 4 3 5 5 6 8 7 13 8 21 9 34 10 55and so on. The Fibonacci functions comes up a lot in computer science and also in nature. It turns out that when you divide the nth Fibonacci number by the (n-1)th, you get an approximation to the Golden Ratio, or about 1.618033988, one of those important numbers like Pi and e. The higher the value of n, the better the approximation. Fibonacci numbers also have interesting number theoretical properties. Let's look at a function that computes the nth Fibonacci number:
int F (int n) { int F_i, /* the "current" fibonacci number */ F_i_minus_1, /* the "previous" one */ tmp; /* temporary */ int i; /* we start with i=2, so F(i-1) is 1, F(i) is 1 */ F_i_minus_1 = 1; F_i = 1; /* we know F(1) and F(2), let's get F(3)..F(n) */ for (i=3; i<=n; i++) { /* tmp is F(i) */ tmp = F_i_minus_1 + F_i; /* F(i-1) is previous value */ F_i_minus_1 = F_i; /* F(i) is current value */ F_i = tmp; } /* all done... */ return F_i; }So to get a table of Fibonacci numbers, we can have a simple main like this:
#include <stdio.h> int main () { int i; for (i=1; i<=46; i++) printf ("%d %d\n", i, F(i)); return 0; }(Why 46? F(47) overflows a 32-bit integer; these numbers get big fast.)
int factorial (int n) { int i, product; product = 1; for (i=1; i<=n; i++) product = product * i; return product; }But we can just directly code the function from the definition instead of doing the algorithm:
int factorial (int n) { if (n == 0) return 1; else return n * factorial (n - 1); }So factorial is calling upon itself to figure out values of the factorial function for different values of n. You can think of each invokation of factorial as a separate "copy," with its own n parameter.
#include <stdio.h> void print_between (int first, int last) { int i; for (i=first; i<=last; i++) printf ("%d\n", i); } int main () { int n, m; printf ("Enter two numbers: "); scanf ("%d %d", &n, &m); print_between (n, m); return 0; }So far so good, it's pretty clear what's going on here. Now let's rewrite the print_between function, this time using recursion:
void print_between (int first, int last) { if (first <= last) { /* base case */ printf ("%d\n", first); print_between (first+1, last); } }When we call this function with, say print_between (2, 6), the following sequence occurs:
Function Call Output print_between (2, 6); printf ("%d", 2); 2 print_between (3, 6); printf ("%d", 3); 3 print_between (4, 6); printf ("%d", 4); 4 print_between (5, 6); printf ("%d", 5); 5 print_between (6, 6); printf ("%d", 6); 6 return return return return return(The returns are where each function call ends.) What good is this? Not much, it's just a contrived example of recursion. But what happens if we switch the order of the printf and recursive function call:
void print_between (int first, int last) { if (first <= last) { /* base case */ print_between (first+1, last); printf ("%d\n", first); } }That simple change causes the function to print the sequence backwards:
Function Call Output print_between (2, 6); print_between (3, 6); print_between (4, 6); print_between (5, 6); print_between (6, 6); printf ("%d", 6); 6 return printf ("%d", 5); 5 return printf ("%d", 4); 4 return printf ("%d", 3); 3 return printf ("%d", 2); 2 returnEach recursive function call "remembers" it's own value for last, and prints it out after recursively calling print_between. What good is this? Okay, it's still not much good; we could still do it with stuff we already know like a for loop.
#include <stdio.h> void print_backwards (void) { float f; /* read in a number */ scanf ("%f", &f); /* if not the end of input... */ if (f != -1.0) { /* f == -1 is the base case */ /* recursively get more numbers */ print_backwards (); /* print the current number */ printf ("%f\n", f); } } int main () { printf ("Enter some numbers, followed by -1: "); print_backwards (); }Let's take another look at the Fibonacci function, this time recursively:
int F (int n) { if (n == 1 || n == 2) return 1; /* base case */ return F(n-1) + F(n-2); }The old version was about fourteen lines of C code. This is four lines, with no variables. More efficient, right? Wrong; this function takes a lot more time because it needlessly recomputes many factorial values. Although we can try to make this one faster using arrays (from the next chapter), in general recursive functions are a little more time consuming than their iterative cousins. Doing a function call in machine language takes a fair amount of time compared to doing one iteration of a loop, so sometimes recursion is less efficient. Sometimes, though, it is the most natural way of looking at a problem and makes the code more readable.
Please begin reading Chapter 5 in your book.