Lecture 1b: Recursion


Lecture

Induction and Logic

The general idea is like eating an apple. You don't swallow it whole (unless you're Chuck Norris and need... you know). You always want to eat the apple one bite at a time... without eating the core and all that apple seeds.

You always start with what you know and you try to use repetitive steps of known operations to get you to an unknown, which will then become a known.

Example 1:

What if you don't know how to multiply?

4*4 = ???

4*4 = 4 + (4*3) = 4 + 4 + (4*2) = 4 + 4 + 4 + (4*1) = 4 + 4 + 4 + 4 = 16

If we observe this we have to say what we know, what our goal is and how do we get there:

Goal: Solution for 4x4
Known: 4*1 = 4 (one of 4 is just 4)
Step towards goal: 4*n = 4 + 4*(n-1)

This technique is what's called Divide and Conquer... sort of like what the Roman empire did, as opposed to what Alexander the Great did.

Recursion in Java/C++

What does recursion look like in code? We start by stating the same three criteria and convert it into code.

Example 2:

So how do you implement your own power function?

Goal: Solution for a^b
Known: a^1 = a (or if you are really hardcore, a^0 = 1)
Steps toward goal: a^n = a * a^(n-1)

double pow (double a, double b){

if (b == 1) //Known
  return a;

return a * pow(a, b-1); //Step toward goal

}

Example run (NOTE: this was when known goes down to 0):

Notice how every call to pow will force the computer to give you a new "frame" for that function call... nothing persists between the function calls. This is VERY important!!!

Why recursion instead of loops?

The first, and only reason you should focus on for now, is that recursion cleans up the algorithm and makes more sense sometimes.

The real reason is that, though loops are good for static problems, it can't overcome the intrinsic nature of dynamic data structures. Especially when you are not really sure where the algorithm is going, you need something that is more generic... which is what recursion provides. More will be said on this when we look at sorting algorithms and dynamic data structures.

Example 3:

The famous greatest common denominator (GCD) algorithm by Euclid. Recursive solution may be much cleaner than iterative solution. Note, good design would check for negative inputs and other things... but let's just focus on recursion.

Recursive:

/**
 * from http://www.java-tips.org/java-se-tips/java.lang/finding-greatest-common-divisor-recursively.html

 * Return the greatest common divisor
 */
 
 public static long gcd(long a, long b) {
 
   if (b==0
     return a;
   else
     return gcd(b, a % b);
 

Iterative:

  // from: http://www.merriampark.com/gcd.htm
  public static long euclidAlgorithmIterative (long u, long v) {

    long gcd = 0;
    long r = 0;

    while (true) {
      if (v == 0) {
        gcd = u;
        break;
      }
      else {
        r = u % v;
        u = v;
        v = r;
      }
    }

    return gcd;
}

In class exercise

  1. Display the Fibonacci sequence up to the N-th number using a recursive algorithm. For definitions, refer to the Wikipedia page for it. Solution
  2. Recursively convert any decimal number into binary, or any other radix.

Video Apples to Apples entries

Green Apple: Mouthover

Red Apples:

Anthony: The Juggernaut B** (Warning: Explicit language)
Jasper: Crazy Indian Video... Benny Lava and the honey buns (Because I'm the moderator this automatically disqualifies)