CS103L SPRING 2017
UNIT 8: RECURSION
TEXT
RECURSION
▸ A recursion function is defined in terms of itself
▸ Applies to math, e.g. recursion relations, sequences
▸ Fibonacci: F0 = 1, F1 = 1, Fn = Fn-1 + Fn-2
▸ Applies to computer functions that call themselves
▸ Also, nerdy CS acronyms
▸ GNU = GNU is Not Unix
TEXT
RECURSIVE FUNCTIONS
▸ To write recursive functions we break up the problem into two cases:
▸ #1 A smaller version of the same problem
▸ #2 A “base case” of the problem where the answer is known ahead of time, or easily computed
▸ All recursive functions *must* have a base case - or what?
▸ Factorial Example: n! = n*(n-1)*(n-1)…*1
▸ factorial(n):
▸ factorial(1) = 1 (base case)
▸ factorial(n) = n*factorial(n-1) (recursive case)
TEXT
FACTORIAL EXAMPLE
unsigned long fact(unsigned long n)
//base case
if(n == 1) return 1;
unsigned long r = fact(n-1); //recursive case
return n * r
}
TEXT
TRACING RECURSIVE CODE
fact(n=3) fact(n=2) fact(n=1)
r = fact(n-1) r = fact(n-1) return 1
return 3 * 2 return 2 * 1
TEXT
TWO TYPES OF RECURSIVE FUNCTIONS
▸ Recursive functions can be classified in two type: head recursion, tail recursion
▸ Head Recursion: immediately make the recursive call then do some work
▸ Tail recursion: do some work, then make the recursive call
void stopgo(int n) void gostop(int n)
{ {
if(n==1) { if(n==1) {
cout << “Stop.” << endl; cout << “Stop.” << endl;
return;
return;
} }
gostop(n-1); cout << “Go” << endl;
cout << “Go” << endl; gostop(n-1);
} }
TEXT
int main()
{
RECURSIVE FUNCTIONS int data[4] = {8, 6, 7, 9};
int sum1 = isum_it(data, 4);
int sum2 = rsum_it(data, 4);
▸ Recursive functions usually take the place of }
loops int isum_it(int data[], int len)
{
sum = data[0];
▸ Example: summing up an array of integers for(int i=1; i < len; i++){
sum += data[i];
}
}
int rsum_it(int data[], int len)
{
if(len == 1)
return data[0];
else
int sum = rsum_it(data, len-1);
return sum + data[len-1];
}
TEXT
TRACING RECURSIVE SUM
data[4] =
{8,6,7,9};
rsum_it(data, 4) rsum_it(data, 3) rsum_it(data, 2) rsum_it(data, 1)
int sum = int sum = int sum = return data[0]
rsum_it(data, 4-1) rsum_it(data, 3-1) rsum_it(data, 2-1)
sum = 21 sum = 14 sum = 8
return 21 + data[3] return 14 + data[2] return 8+data[1]
System
tem StackStack & Recursion
& Recursion
int main() int main()
{
{
tack
tem makes
stack recursion
TEXT makes recursion
int data[4] = {8, 6, 7, 9};
int data[4]
int sum2 = rsum_it(data, 4); = {8, 6, 7, 9};
int sum2 = rsum_it(data, 4);
roviding separate }
eage
byfor
providing
the local
separate }
int rsum_it(int data[], int len)
{
each
STACK
y storage MAKES
runningfor
RECURSION POSSIBLE
int rsum_it(int data[], int len)
the local return data[0];
instance
if(len == 1)
{
if(len == 1)
es
on ▸
of How
each does this
running work: we
instance
else call
int sum =
the *same*
return function over and over?
data[0];
else
rsum_it(data, len-1);
unction
▸ Because of the stack! We can call the function as many times as need be,
int sum =
return sum + data[len-1];
} rsum_it(data, len-1);
each gets its *own* stack
Code for all functions
frame: hence
return sum + each has it’s
data[len-1]; own stack-local variables
}
Code
forfor all functions 800
ata rsum_it
Code(data=800,
for all functions int main()
=1, sum=??) and return link 8 6 7 9
{
ata for rsum_it (data=800, data[4]: 0 1 2 3
n=2,
=2, sum=??)
sum=8) Code
Data for
and
and for
returnall
rsum_it
return link
linkfunctions
(data=800, 800 int data[4] = {8, 6, 7, 9};
ata forlen=1,
rsum_itsum=??) and return link
(data=800, 8 6 int
7 9 sum2 = rsum_it(data, 4);
=3, sum=14)
sum=??) and return link }
Data for rsum_it (data=800, data[4]: 0 1 2 3
ata forlen=2,
rsum_it (data=800,
len=2, sum=??)
sum=8) and
and return
return link
link
=4, sum=21)
sum=??) and return link int rsum_it(int data[], int len)
for main Data for rsum_itand(data=800,
(data=800,sum2=??) {
len=3, sum=??) and return link
sum=14)
return link
if(len == 1)
Data
System forarea
stack rsum_it (data=800,
len=4, sum=21)
sum=??) and return link
return data[0];
Data for main (data=800,sum2=??) and
else
return link int sum = rsum_it(data, len-1);
return sum + data[len-1];
System stack area
}
TEXT
IN CLASS EXERCISE
▸ count-up
▸ count-down
TEXT
REQUIREMENTS FOR RECURSIVE FUNCTIONS
▸ You must have at least one base case!
▸ This case must terminate the recursion, i.e it will not make a further recursive
call
▸ It is possible to have more than one base case
▸ The recursive case must “make progress” towards the base case
▸ The problem must get “smaller” each time… or?
▸ Recursive cases and base cases must have return statements to propagate the
answer “up” the recursive call stack
TEXT
LOOPS VS. RECURSION
▸ FAQ: is it better to use loops or recursion?
▸ All recursive solutions can be done with iterative solutions
▸ Recursion pros:
▸ Clean and elegant code, easy to read
▸ Usually recursive code is much simpler than iterative
▸ Sometime iterative code is *nearly impossible* to write!
▸ Power of recursion comes from making multiple recursive calls - hard to implement with iterative solutions
▸ How to choose?
▸ Iteration is faster/less memory
▸ But if implementation is difficult or inscrutable - use recursion
14
Recursive Binary Search
TEXT
k = 11
• Assume
RECURSIVE remaining items = [start, end)
EXAMPLES List 2 3 4 6 9 11 13 15 19
– start is inclusive index of start item in remaining list index 0 1 2 3 4 5 6 7 8
▸ Recursive Binary – End is exclusive index of start item in remaining list
Search start i end
• binSearch(target, List[], start, end)
▸ Is a given element, k, in an array? If yes, return index, otherwise return -1
List 2 3 4 6 9 11 13 15 19
– end
▸ Initialize start, mid, Perform base check (empty list) index 0 1 2 3 4 5 6 7 8
• Return NOT FOUND (-1)
▸ binsearch(k, list, start, end): start i end
▸
– Pick mid item
base case: start = end
List 2 3 4 6 9 11 13 15 19
– Based on comparison of k with List[mid]
return list[start] == k ? start : -1 index 0 1 2 3 4 5 6 7 8
▸
• EQ => Found => return mid
▸ Recursive case: start i end
• LT => return answer to BinSearch[start,mid)
▸ compute mid • GT => return answer to BinSearch[mid+1,end)
List 2 3 4 6 9 11 13 15 19
▸ if (list[mid] == k) return mid; index 0 1 2 3 4 5 6 7 8
▸ else if(list[mid] > k) return binsearch(k,list,start,mid);
start end
▸ else return binsearch(k,list,mid,end); i
15
Sorting
TEXT
• If we have an unordered list, sequential List 7 3 8 6 5 1
RECURSIVE EXAMPLES
search becomes our only choice index 0 1 2 3 4 5
Original
▸ Recursive•Bubble
If we Sort
will perform a lot of searches it may List
index
3 7 6 5 1 8
0 1 2 3 4 5
be beneficial to sort the list, then use After Pass 1
▸ List with indexes 0 -search
binary (n-2)
List 3 6 5 1 7 8
• Many
▸ Scan list and swap sorting algorithms
to “bubble” largest of differing
value to the right
index 0 1 2 3 4 5
After Pass 2
complexity (i.e. faster or slower)
▸ Recurse on list indexes 0 - (n-2), then 0 - (n - 3), etc. List 3 5 1 6 7 8
• Bubble Sort (simple though not terribly index 0 1 2 3 4 5
After Pass 3
efficient)
List 3 1 5 6 7 8
– On each pass through thru the list, pick up the index 0 1 2 3 4 5
maximum element and place it at the end of After Pass 4
the list. Then repeat using a list of size n-1 (i.e. List 1 3 5 6 7 8
w/o the newly placed maximum value) index 0 1 2 3 4 5
After Pass 5
TEXT
IN CLASS EXERCISE
▸ Text Fractal
TEXT
CODING TIME!
▸ Examples to code: ▸ Examples to code:
▸ recursive sum ▸ Recursive Insertion sort
▸ index version
▸ Fibonacci
▸ pointer version
▸ Recursive binary search
▸ index version
▸ pointer version
▸ Recursive Bubble sort