Lecture 2 Feb 3, 2009 goals: continue recursion more examples of recursive programs
Recursion - rules Rule 1: Provide exit from recursion. (focus on base cases – some times, more than one base case is needed.) Rule 2: Make sure that the successive recursive calls progress towards the base case. Rule 3: Assume that recursive calls work. Rule 4: Compound interest rule: Avoid redundant calls.
Recursion – simple examples 1)Compute n! iter: n! = 1 x 2 … x n = (n – 1)! x n rec: f(n) = n * f(n – 1) 2) Compute … + n rec: f(n) = n + f(n – 1) 3) Compute the n-th Fibonacci number f(n) = f(n – 1) + f(n – 2)
Example: (from Chapter 2 of text) Given x and n, we want to compute x n. Obvious iterative solution: int exp(int x, int n) { int temp = x; for (int j= 1; j < n; ++j) temp*= x; return temp; } The number of multiplications performed is n – 1. We will now see that a recursive algorithm will provide a much faster solution. Faster algorithm is crucial for RSA encryption algorithm.
Idea behind the algorithm Rule of exponents: x n = (x 2 ) n/2 if n is even x * (x 2 ) (n-1)/2 if n is odd base case n = 1 return x even n call exp(x*x, n/2) and return the result. odd n call exp(x*x, (n – 1)/2) and multiply the result of call by x and return the output.
Code for recursive exponent algorithm int exp (int x, int n) { if (n == 1) return x; else if (n%2 == 0) return exp(x*x, n/2); else return x* exp(x*x, (n – 1)/2); } Fact: When called to compute exp(x,100000), the iterative algorithm performs multiplications while the recursive algorithm will performs 21 multiplications. Note: The above recursive function is slightly different from the recursive function we presented in the lab.
Recursion involving 1-dim array data Given two segments of sorted arrays A and B, output the result of merging them as a single sorted array. A B merge(A, 2, 3, B, 9, 13) should return merge(A, 2, 2, B, 9,10) should return the array merge(A, 3, 4, B, 9, 8) should return 5 7 since the second array is empty. (high index < low index means the array is empty.)
What are the base cases?
one array segment is empty. In this case, what is the output?
What are the base cases? one array segment is empty. In this case, what is the output? The other array segment, so we just have to copy the segment to the output.
What are the base cases? one (or both) array segment is empty. In this case, what is the output? The other array segment, so we just have to copy the segment to the output. what if both segments are not empty? We need to make recursive call.
Before we proceed, we need to make a change to the prototype of the function merge. Why? We need to add two more parameters - the name of the array and the starting index in the output array at which we want to write.
AB merge(A, 2, 3, B, 9, 13, C, 3) should return C
merge(A, low1,high1, B, low2, high2, C, low) A B merge(A, 9, 13, B, 2, 3, C, 0) Case 1: A[low1] < B[low2] Example: C
merge(A, low1,high1, B, low2, high2, C,low) A B merge(A, 9, 13, B, 2, 3, C, 0) Case 1: A[low1] < B[low2] Example: Step1: move A[low1] to C[low]. Now a recursive call to merge will get the rest of the job done. What call?
merge(A, low1,high1, B, low2, high2) A B merge(A, 9, 13, B, 2, 3) Case 1: A[low1] < B[low2] Example: Step1: move A[low1] to C[low]. Now a recursive call to merge will get the rest of the job done. What call? merge(A, low1+1, high1, B, low2,high2, C, low + 1)
Case 2: A[low1] >= B[low2]. Move B[low2] to C[low] and make a recursive call to merge(A,low1, high1, B, low2+1, high2, C, low+1) The complete code is shown below:
void merge(int A[], int low1, int high1, int B[], int low2,int high2, int C[], int low) { if (high1 < low1) copy(B, low2, high2, C,low); else if (high2 < low2) copy(A, low1, high1, C,low); else if (A[low1] < B[low2]) {C[low] = A[low1]; merge(A,low1+1, high1, B, low2, high2, C,low + 1);} else {C[low] = B[low2]; merge(A,low1, high1, B, low2+1, high2, C,low + 1); } void copy(int A[], int s, int t, int B[], int s1) { for (int j= s; j<= t; ++j) B[s1 +j - s] = A[j]; }
Last example: recursion with a linked list Suppose we want to insert a key x as a last item of a list. a k g c x = ‘b’ a k g c b
void insertLast(Node& head, int k) { // insert k as the last item of the list whose // header is pointed to by head Node* tmp = new Node(k); if (head == 0) head = tmp; else insertLast(head->next, k); }