# Thursday February 5, 1998

• Programming Abstractions in C: 5.1-5.2

Handouts (available on-line): none

Topics Covered:

• The Fibonacci numbers are defined recursively, so we can easily write a program with a recursive function that computes the nth Fibonacci number. ( Sample run.)
• Note the use of argc and argv in the parameter list of the main function. These parameters allow us to access the command line arguments that were typed in at the UNIX prompt.
• This program is really slow. It took 3 minutes and 22 seconds to compute the 42nd Fibonacci number. The reason is that the fib() function is called over and over again for the same values. For example, to compute fib(n), the value of fib(1) is computed fib(n-1) times. Since the Fibonacci numbers grow very quickly, this makes our program very slow.
• One way to fix the problem of repeatedly computing the same values of fib(i) is to use a memoization table. (Note: the word is not "memorization".) In this approach, after we compute the value of fib(i) for the first time, we record it in the memoization table. If the function fib() is called with parameter i again, the value from the table is retrieved and returned. This approach reduces the number of recursive calls dramatically and gives us a much faster program. The sample run shows that the new running time to compute fib(42) is less than 0.1 seconds.

• The greatest common divisor (gcd) of two numbers m and n is the largest integer that divides both m and n. We show how recursion is used to find a fast algorithm to compute gcd.
• First, we implement a naive algorithm to compute the gcd of two numbers. This program simply tries every number between 2 and the smaller of m and n. The largest divisor is returned. The sample run shows that this program is quite slow. It took 22 seconds in one case to compute the gcd of two large-ish numbers.
• Euclid, an ancient Greek mathematician, showed that
gcd(m,n) = gcd(n, m % n).
Using Euclid's recursive algorithm, we can produce a faster program to compute the gcd of two numbers. The sample run shows a running time of less than 0.1 seconds for the same input that took 22 seconds previously. Note that the worst case input to Euclid's gcd algorithm is two consecutive Fibonacci numbers.
• We can also implement Euclid's algorithm using a while loop instead of recursion. (Program and sample run.) With modern optimizing compilers, this program isn't necessarily faster than the recursive version. One disadvantage of not using recursion is that Euclid's original formulation is lost.

• Another classic example of problem solving by recursion is the Towers of Hanoi problem. Program and sample run.

• Finally, we looked at an example of mutually recursion where two functions call each other. In our program, the function count_alpha() does not call itself directly, but does call the function count_non_alphas(). Since count_non_alphas() also calls count_alpha(), the execution of count_alpha() does not return before another call to count_alpha() is issued. Hence we must take great care to ensure that the recursion terminates properly. In this program, we rely on the null character at the end of the string to trigger the base case of the recursion. See sample run.