Recursion
You might find these notes useful: Recursion lecture slides from 15-110
A recursive function is one that calls itself.
Not necessarily infinitely, because you can make the recursive call based on a condition.
Every recursive function has two parts:
- The base case: One or more simple cases that can be solved directly and immediately (non-recursively).
- Recursive cases: One or more cases that can be solved by solving simpler versions of the original problem.
Example: Adding two non-negative integers
Adding zero is trivial: Any number plus zero equals the number. That’s our base case:
1 2 3 |
function adder(a, b) { if (b == 0) return a; } |
How can we simplify a + b and make it closer to a + 0? Let’s assume we know how to add 1 or subtract 1. That’s simpler than full addition, right? We’ll use the property that a + b = (a + 1) + (b – 1) to make the recursive case:
1 2 3 |
function adder(a, b) { if (b > 0) return adder(a + 1, b - 1); } |
Neither one of these is a full solution, but if we put them together we have an adder!
1 2 3 4 5 6 7 |
function adder(a, b) { if (b == 0) { return a; // base case } else { // recursive case (b > 0) return adder(a + 1, b - 1); } } |
Let’s look at what happens with adder(4, 3):
1 2 3 4 5 6 7 8 |
adder(4, 3) calls ... adder(5, 2) which calls ... adder(6, 1) which calls ... adder(7, 0) which returns ... 7 so adder(6, 1) returns 7 so adder(5, 2) returns 7 so adder(4, 3) returns 7 |
Recursion with Graphics
function setup() {
createCanvas(400, 400);
frameRate(10);
}
function draw() {
background(240);
fill(0);
recPattern(80, 80, 243);
}
function recPattern(x, y, size)
{
// base case:
if (size <= 2) {
rect(x, y, size, size);
} else { // recursive case:
// draw smaller pattern in corners and center
var third = size / 3;
recPattern(x, y, third); // upper left
recPattern(x + 2 * third, y, third); // upper right
recPattern(x + third, y + third, third); // middle
recPattern(x, y + 2 * third, third); // lower left
recPattern(x + 2 * third, y + 2 * third, third); // lower right
}
}
Recursive Music!
Recursive Search Problem
Recursion is an alternative to iteration. In class, we did 2 “warm-up” exercises: recursive function to print 0 through N, recursive function to print elements of an array, and then implemented linear search with recursion.
Print 0 through N using recursion
The recursive description of this problem is: To print i through N, print i, then print i+1 through N. The base case is print nothing when i > N.
Here’s a solution:
1 2 3 4 5 6 7 8 9 10 11 12 |
// print numbers from i through lastNum function counter(i, lastNum) { // base case: nothing left to print if (i > lastNum) { return "done"; } // recursive case: println(i); return counter(i + 1, lastNum); } // to print 0 through 10, call counter(0, 10) |
Print elements of an array
Similar to just printing 0 through N, we print a[0] through a[N-1], where N is the length.
1 2 3 4 5 6 7 8 9 10 11 12 |
// print values in an array function printer(i, a) { var len = a.length; // base case if (i >= len) { return; } // recursive case println(a[i]); printer(i + 1, a); } // to call print the elements in ar, call printer(0, ar) |
Recursive Implementation of Linear Search
Implement linear search recursively, starting with this code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
function setup() { var ar = [3, 5, 6, 8, 3, 65, 4, 7, 5] println(findNum(ar, 65, 0)); // should find 65 at index 5 println(findNum(ar, 100, 0)); // should not find 100, prints -1 } // find x in a, starting at location i // if found, return the location // if not found, return -1 function findNum(a, x, i) { // add code here } |
Here’s a solution:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
// return index of x in a // if a[i] == x, then return i // otherwise return -1 function findNumHelper(i, x, a) { // base case: // if nothing left, we're done: -1 if (i > a.length) { return -1; } else if (a[i] == x) { return i; } else { // recursive case: return findNumHelper(i + 1, x, a); } } // findNumHelper(0, x, a) does the job, but we can make // things slightly prettier by eliminating the need to // pass in zero; for that we just define another function // to call findNumHelper(): function findNum(x, a) { return findNumHelper(0, x, a); } // here's a test function setup() { var ar = [3, 5, 6, 8, 3, 65, 4, 7, 5]; var x = 65; println(findNum(x, ar)); } |