210 likes | 374 Views
Introduction to Data Structures and Algorithms. Chapter 6 Recursion (1). Recursion. Recursion Definition Process: Expand: A function calls itself with “smaller parameter” Converge: A function with parameter x uses the computation result of function with x-1.
E N D
Introduction to Data Structures and Algorithms Chapter 6 Recursion (1)
Recursion Recursion Definition • Process: • Expand: A function calls itself with “smaller parameter” • Converge: A function with parameter x uses the computation result of function with x-1. • When terminate the sequence of recursive calls? • Base case: • A function call with the smallest parameter needs no further calls; it simply returns result.
Sum of Squares int SumSquares(int m, int n) { if (m < n) return m*m + SumSquares (m+1,n); else return m*m; }
Factorials Computation • N ! = N × (N-1) × (n-2) × … × 1 • Another way to compute factorial? • Instead of computing factorial, computing multiplication • Basic Idea (tree structure): • N ! = N × (N -1) ! • (N -1) ! = (N -1) × (N -2) ! • … • 1! = 1
int factorial(int n) { int result =1; for (int j=n; j>=1; j--) result *= j; return result; } int factorial(int n) { if (n==1) return 1; else return ( n * factorial (n-1) ); }
Reversing a List • Partition the list into • Head --- one node • Tail --- the rest of the list • Reverse the head and the tail (recursively) • Combine the two reverse lists
Functions • getHead • getTail • Node getHead( List mlist), returns the first node • List getTail (List mlist), returns the sublist that results after removing the first node • List Concat (List m1, List m2), joins two sublists
Recursive Reverse List List reverseL (List mlist) { List head; List tail; if (mlist.first == null) return null; else { head = getHead(mlist); tail = getTail(mlist); return concat (reserseL (tail), head); } }
Binary Search • Binary Search Algorithm (Chapter 2): • Order array elements • Compare the value of middle element with target • Based on comparison result, change range and middle element • Keep doing that until a match is found • Note that each time we apply same logic to different range and middle element • Can it be done recursively? How? • Develop a function called recFind(key, LowerBond, Upper Bound) • If key < middle element • recFind (key, LowerBound, Middle-1) • If key > middle element • recFind (key, Middle+1, UpperBound)
private int recFind(long searchKey, int lowerBound, int upperBound) { int curIn; curIn = (lowerBound + upperBound ) / 2; if(a[curIn]==searchKey) return curIn; // found it else if(lowerBound > upperBound) return nElems; // can't find it else // divide range { if(a[curIn] < searchKey) // it's in upper half return recFind(searchKey, curIn+1, upperBound); else // it's in lower half return recFind(searchKey, lowerBound, curIn-1); } // end else divide range } // end recFind()
Anagrams • All possible permutations of the input string • Example: anagrams of cat • cat; cta; atc; act; tca; tac • Problem: how to compute all anagrams • Loop idea: many levels of loop • Recursive Idea: • Anagrams(S) = the first character + anagrams (S-1) • How many choices for the first character ? • Anagrams (S-1) is different for each possible choice
Anagramming Recursive Algorithm • Anagram the rightmost n-1 letters • Shift n letters to left by one postion • cat – atc – tca -- cat • Repeat these steps n times • Trace anagramming recursive algorithm for the word “cat” • Figure 6.7
public static void doAnagram(int newSize) { int limit;if(newSize == 1) // base case return; // go no further for(int j=0; j<newSize; j++) // for each position, {doAnagram(newSize-1); // anagram remaining if(newSize==2) // if innermost, displayWord(); // display it rotate(newSize); // rotate word } }
// rotate left all chars from position to end public static void rotate(int newSize) { int j; int position = size - newSize; char temp = arrChar[position]; // save first letter for(j=position+1; j<size; j++) // shift others left arrChar[j-1] = arrChar[j]; arrChar[j-1] = temp; // put first on right }
Tower of Hanoi • Demo • A number of disks placed on three columns • S: source column • I: intermediate column • D: destination column • Rule: • no larger disk is allowed to place on top of smaller disks
Idea: • Sub-tree with fewer disks • Sub-trees are formed many times • Recursive algorithm • Move the sub-tree consisting of the top n-1 disks from S to I • Move the remaining disk (largest) from S to D • Move the sub-tree from I to D
class TowersApp { static int nDisks = 3; public static void main(String[] args) { doTowers(nDisks, 'A', 'B', 'C'); } //----------------------------------------------------------- public static void doTowers(int topN, char src, char inter, char dest) { if(topN==1) System.out.println("Disk 1 from " + src + " to "+ dest); else {doTowers(topN-1, src, dest, inter); // src to inter System.out.println("Disk " + topN + " from " + src + " to "+ dest);doTowers(topN-1, inter, src, dest); // inter to dest } }//------------------------------------------------------------- } // end class TowersApp Trace Algorithm: Page 279
Running time analysis: • Depends on number of recursive calls • Examples: • Factorial O(?) • Binary search O(?) • Anagram O(?)
Divide-and-Conquer approach • divide a big problem into two smaller problems and solve them separately. The process continues until you get to the base case, which can be solved easily • Divide-and-conquer approach usually involves two recursive calls, one for each smaller problems • Lots of time, you will see O(n2) algorithm can be improved to O(nlogn) with Divide-and-conquer approach
Exercise 1: String length computation • Compute the length of an input string recursively • Exercise 2: Teddy Bear Game • Initially, you have initial number of bears • Each step, you can do one of the followings: • Ask for increment number of bears • Give away half of bears if you have even number of bears • Goal: reach goal number of bears within n steps • How do you know if you can reach goal or not?