# Recursion

PGSS Computer Science Core Slides

Fabulously complex structure through simple procedures

### Towers of Hanoi

```    a       b       c

|       |       |
###      |       |
@@@@@     |       |
\$\$\$\$\$\$\$    |       |
----+-------+-------+----
```

We want to move the tower from a, moving one disk at a time, never moving a disk on top of a smaller one.

A simple procedure does this, if it calls itself. This self-use is recursion.

```   Algorithm Hanoi(disk, source, dest, other)
if disk is smallest then
move disk from source to dest
else
Hanoi(next disk, source, other, dest)
move disk from source to dest
Hanoi(next disk, other, dest, source)
fi
```

### A trace

```IN Hanoi(\$\$\$\$\$\$\$, a, b, c)
IN Hanoi(@@@@@, a, c, b)
IN Hanoi(###, a, b, c)
|       |       |
|       |       |
@@@@@     |       |
\$\$\$\$\$\$\$   ###      |
----+-------+-------+----
OUT
|       |       |
|       |       |
|       |       |
\$\$\$\$\$\$\$   ###    @@@@@
----+-------+-------+----
IN Hanoi(###, b, c, a)
|       |       |
|       |       |
|       |      ###
\$\$\$\$\$\$\$    |     @@@@@
----+-------+-------+----
OUT
OUT
|       |       |
|       |       |
|       |      ###
|    \$\$\$\$\$\$\$  @@@@@
----+-------+-------+----
IN Hanoi(@@@@@, c, b, a)
IN Hanoi(###, c, a, b)
|       |       |
|       |       |
|       |       |
###   \$\$\$\$\$\$\$  @@@@@
----+-------+-------+----
OUT
|       |       |
|       |       |
|     @@@@@     |
###   \$\$\$\$\$\$\$    |
----+-------+-------+----
IN Hanoi(###, a, b, c)
|       |       |
|      ###      |
|     @@@@@     |
|    \$\$\$\$\$\$\$    |
----+-------+-------+----
OUT
OUT
OUT
```

### A Useful Example

Alice: I don't want the world to end! Is recursion still useful?
```Algorithm Fast-Exponentiate(x, n)
if n = 0 then
return 1
else if n is even then
return Fast-Exponentiate(x^2, n / 2)
else
return x * Fast-Exponentiate(x^2, (n - 1) / 2)
fi
```
```IN Fast-Exponentiate(2, 10)
10 is even:
IN Fast-Exponentiate(4, 5)
5 is odd:
IN Fast-Exponentiate(16, 2)
5 is odd:
IN Fast-Exponentiate(256, 1)
5 is odd:
IN Fast-Exponentiate(32768, 0)
return 1
return 256
return 256
return 1024
return 1024
```

Correctness: We prove this using induction on n. The base case, when n is 0, is easy: Fast-Exponentiate(x, 0) = 1 = x^0. Say it works for all n smaller than k. Does it work for k? If k is even, then k/2 is smaller than k, so

```  Fast-Exponentiate(x, k) = Fast-Exponentiate(x^2, k / 2)
= (x^2)^(k / 2)
= x^(2(k/2))
= x^k
```
If k is odd, then (k - 1)/2 is smaller than k, so
```  Fast-Exponentiate(x, k) = x * Fast-Exponentiate(x^2, (k - 1) / 2)
= x * (x^2)^((k - 1) / 2)
= x * x^(2((k - 1)/2))
= x * x^(k - 1)
= x^k
```

Time bound: We use a recurrence.

```  T(1) = 1
T(n) < T(n / 2) + 1
```
Using the Master Theorem (see textbook appendix), we see that
```  T(n) = O(log_2 n)
```

### Recursion and Induction

Recursion and mathematical induction have a lot in common.

Like inductive proofs, recursive algorithms must have a base case - some situation where th efunction does not call itself.

Otherwise the program will never get to an answer!

Alice: But this is a good thing with the Tower of Hanoi!

### Recursion in Java

```public static int Factorial(int n) {
if(n == 0) {
return 1;
} else {
return n * Factorial(n - 1);
}
}
```

### More Java recursion

The Fibonacci sequence is the following:

``` 1 1 2 3 5 8 13 21 34 55 ...
```
Each number is the sum of the preceding two numbers in the sequence. We calculate the nth Fibonacci number.

```public static int Fibonacci(int n) {
if(n < 2) {
return 1;
} else {
return Fibonacci(n - 1) + Fibonacci(n - 2);
}
}
```

We can graph what's happening using a call tree.

```                n = 4
___/     \___
/             \
n = 3           n = 2
/     \         /     \
n = 2   n = 1   n = 1   n = 1
/     \
n = 1   n = 1
```

Notice that this takes Fibonacci(n) additions! Since Fibonacci(n) = O(1.618^n), this is a very poor running time. In fact one can calculate it in O(n) time.

### Another Example

```Problem class FIND_IN_SORTED_ARRAY
Input: an array arr sorted in increasing order, an integer n
Output: index of n in arr, -1 if absent
```
```Algorithm Binary-Search(arr, n, low, high)
if high < low then
if arr[low] = n then
return low
else
return -1
fi
else
if arr[(low + high) / 2] < n then
return Binary-Search(arr, n, low, (low + high) / 2)
else if arr[(low + high) / 2] > n then
return Binary-Search(arr, n, (low + high) / 2 + 1, high)
else
return (low + high) / 2
fi
fi
```

This takes O(log_2 n) time. This is the solution to the recurrence relation

```  T(n) < T(n / 2) + O(1)
```

### A Trace

```      +----+----+----+----+----+----+----+----+
arr = |  2 |  3 |  5 |  7 | 11 | 13 | 17 | 19 |
+----+----+----+----+----+----+----+----+

n = 13

IN Binary-Search(arr, 13, 0, 8)
11 < 13:
IN Binary-Search(arr, 13, 5, 8)
17 > 13:
IN Binary-Search(arr, 13, 5, 6)
13 = 13:
RETURN 5
RETURN 5
RETURN 5
```

Each call to a recursive function gets its own copy of variables.

Changing a variable does not change it for higher recursive calls.

```public static int SumSquares(int n) {
int n_squared;
int others;

if(n < 1) {
return 0;
} else {
n_squared = n * n;
others = SumSquares(n - 1);
return n_squared + others;
}
}
```

The call tree looks like this.

```        returns 5
n = 2
n_squared = 4
|
| returns 1
n = 1
n_squared = 1
|
| returns 0
n = 0
```
When the call with n=1 changes n_squared, it just changes its copy of n_squared. The n_squared for the call with n=2 remains unchanged.