UNIT 8: RECURSIONCS103L SPRING 2017
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)
r = fact(n-1)
return 3 * 2
fact(n=2)
r = fact(n-1)
return 2 * 1
fact(n=1)
return 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 callvoid gostop(int n)
{
if(n==1) {
cout << “Stop.” << endl;
return; }
cout << “Go” << endl;
gostop(n-1);
}
void stopgo(int n)
{
if(n==1) {
cout << “Stop.” << endl;
return; }
gostop(n-1);
cout << “Go” << endl;
}
TEXT
RECURSIVE FUNCTIONS
▸ Recursive functions usually take the place of loops
▸ Example: summing up an array of integers
int main(){ int data[4] = {8, 6, 7, 9}; int sum1 = isum_it(data, 4); int sum2 = rsum_it(data, 4);}
int isum_it(int data[], int len){ sum = data[0]; 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)
int sum = rsum_it(data, 4-1)
sum = 21
return 21 + data[3]
rsum_it(data, 3)
int sum = rsum_it(data, 3-1)
sum = 14
return 14 + data[2]
rsum_it(data, 2)
int sum = rsum_it(data, 2-1)
sum = 8
return 8+data[1]
rsum_it(data, 1)
return data[0]
TEXT
STACK MAKES RECURSION POSSIBLE▸ How does this work: we call the *same* function over and over?
▸ Because of the stack! We can call the function as many times as need be, each gets its *own* stack frame: hence each has it’s own stack-local variables
10
Code for all functions
System Stack & Recursion• The system stack makes recursion
possible by providing separate memory storage for the local variables of each running instance of the function
System stack area
System Memory
(RAM)
Code for all functions
int main(){
int data[4] = {8, 6, 7, 9}; int sum2 = rsum_it(data, 4);
}
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];
}
Data for rsum_it (data=800, len=4, sum=??) and return link
Data for rsum_it (data=800, len=3, sum=??) and return link
Data for rsum_it (data=800, len=2, sum=??) and return link
Data for rsum_it (data=800, len=1, sum=??) and return linkData for rsum_it (data=800, len=2, sum=8) and return link Data for rsum_it (data=800,
len=3, sum=14) and return link Data for rsum_it (data=800,
len=4, sum=21) and return link Data for main (data=800,sum2=??) and
return link
8 6 7 90 1 2 3data[4]:
800
int main(){ int data[4] = {8, 6, 7, 9}; int sum2 = rsum_it(data, 4);}
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];}
10
Code for all functions
System Stack & Recursion• The system stack makes recursion
possible by providing separate memory storage for the local variables of each running instance of the function
System stack area
System Memory
(RAM)
Code for all functions
int main(){ int data[4] = {8, 6, 7, 9}; int sum2 = rsum_it(data, 4);
}
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];
}
Data for rsum_it (data=800, len=4, sum=??) and return link
Data for rsum_it (data=800, len=3, sum=??) and return link
Data for rsum_it (data=800, len=2, sum=??) and return link
Data for rsum_it (data=800, len=1, sum=??) and return linkData for rsum_it (data=800,
len=2, sum=8) and return link Data for rsum_it (data=800,
len=3, sum=14) and return link Data for rsum_it (data=800,
len=4, sum=21) and return link Data for main (data=800,sum2=??) and
return link
8 6 7 90 1 2 3data[4]:
800
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
TEXT
RECURSIVE EXAMPLES
▸ Recursive Binary Search
▸ Is a given element, k, in an array? If yes, return index, otherwise return -1
▸ Initialize start, mid, end
▸ binsearch(k, list, start, end):
▸ base case: start = end
▸ return list[start] == k ? start : -1
▸ Recursive case:
▸ compute mid
▸ if (list[mid] == k) return mid;
▸ else if(list[mid] > k) return binsearch(k,list,start,mid);
▸ else return binsearch(k,list,mid,end);
14
Recursive Binary Search
• Assume remaining items = [start, end) – start is inclusive index of start item in remaining list
– End is exclusive index of start item in remaining list
• binSearch(target, List[], start, end)– Perform base check (empty list)
• Return NOT FOUND (-1)
– Pick mid item
– Based on comparison of k with List[mid]• EQ => Found => return mid
• LT => return answer to BinSearch[start,mid)
• GT => return answer to BinSearch[mid+1,end)
2 3 4 6 9 11 13 15 19Listindex
2 3 4 6 9 11 13 15 19Listindex
i
k = 11
endstart
i endstart
2 3 4 6 9 11 13 15 19Listindex
endstart i
0 1 2 3 4 5 6 7 8
0 1 2 3 4 5 6 7 8
0 1 2 3 4 5 6 7 8
2 3 4 6 9 11 15 19Listindex
endstarti
0 1 2 3 4 5 6 7 813
TEXT
RECURSIVE EXAMPLES
▸ Recursive Bubble Sort
▸ List with indexes 0 - (n-2)
▸ Scan list and swap to “bubble” largest value to the right
▸ Recurse on list indexes 0 - (n-2), then 0 - (n - 3), etc.
15
Sorting• If we have an unordered list, sequential
search becomes our only choice• If we will perform a lot of searches it may
be beneficial to sort the list, then use binary search
• Many sorting algorithms of differing complexity (i.e. faster or slower)
• Bubble Sort (simple though not terribly efficient)– On each pass through thru the list, pick up the
maximum element and place it at the end of the list. Then repeat using a list of size n-1 (i.e. w/o the newly placed maximum value)
7 3 8 6 5 1Listindex
Original1 2 3 4 50
3 7 6 5 1 8Listindex
After Pass 11 2 3 4 50
3 6 5 1 7 8Listindex
After Pass 21 2 3 4 50
3 5 1 6 7 8Listindex
After Pass 31 2 3 4 50
3 1 5 6 7 8Listindex
After Pass 41 2 3 4 50
1 3 5 6 7 8Listindex
After Pass 51 2 3 4 50
TEXT
IN CLASS EXERCISE
▸ Text Fractal
TEXT
CODING TIME!
▸ Examples to code:
▸ recursive sum
▸ index version
▸ pointer version
▸ Recursive binary search
▸ index version
▸ pointer version
▸ Recursive Bubble sort
▸ Examples to code:
▸ Recursive Insertion sort
▸ Fibonacci