210 likes | 441 Views
Recursion. Ellen Walker CPSC 201 Data Structures Hiram College. Divide & Conquer. To solve a big problem, break it down into smaller problems Examples: Find the largest element in a list by comparing pairs of elements
E N D
Recursion Ellen Walker CPSC 201 Data Structures Hiram College
Divide & Conquer • To solve a big problem, break it down into smaller problems • Examples: • Find the largest element in a list by comparing pairs of elements • Binary search: find an element in a list by deciding which half of the list it is in, and sorting the smaller half-list
Recursion • Every smaller problem (except the smallest one) is an instance of the larger problem • Examples: • Binary Search • Factorial • Fibonacci number • Implementation: function that calls itself
Sequential Search as Recursion //Find (the first instance of) element in list • If the list is empty, return “not found” • Else if the first element of the list is the one you’re looking for, return it • Else search in the smaller list starting from the second element of the list
Sequential Search in Java //Check if value is in array of integers //Note: end is one value beyond the last in list boolean search1 (int value, int[] list, int st, int end){ if (st==end) return false; // empty list if (list[st]==value) return true; return search1(value, list, st+1, end); }
Sequential Search as Divide & Conquer • Divide the problem into two smaller problems: • Is the value the first element of the list? • Find the value in the smaller list starting at the second element. • Disadvantage: each “smaller” problem isn’t very much smaller
Binary Search • Is the element in the first or second half of the list? (For a sorted list, this is a single comparison to the middle element) • Search for the element in the appropriate half of the list
Binary Search in Java boolean search2(int val, int[] list, int st, int end){ if (st==end) return false; //empty list int middle = (end-st)/2; if (list[middle]==val) return true; if (val < list[middle]) return search2(val,list,st,middle)); else return search2(val, list, middle+1, end); }
Binary vs. Sequential • Sequential search: each list search is 1 smaller • Binary search: each list search is half as big • Binary search is faster, but… • Binary search requires a sorted list
Aspects of A Recursive Solution • Base case (or basis or degenerate case) • List is empty, List has 1 element • Recursive call • Call to search1 or search2 • Recursive call must be “closer” to the base case • The list is shorter in the recursive call
4 Questions for Recursive Algorithm Design • How can you define the problem in terms of a smaller problem of the same type? • “single step” + “smaller problem” • How does each recursive call diminish the size of the problem? • What instance of the problem can serve as the base case? • As the problem size diminishes, will you reach this base case?
4 Answers for Factorial • How can you define the problem… Fact(N) is N*Fact(N-1) • How does each … call diminish… N-1 is smaller than N • What … can serve as the base case? Fact(0) is 1 • …will you reach the base case? Yes, as long as you start with N≥0 (a precondition)
Factorial in Java • Note: this is a “valued” recursive function • The final result is constructed from the results of recursive calls int Fact(int N){ assert (N>=0); //make sure of precondition if (N==0) return 1; else return N*Fact(N-1); }
Activation record • Information recorded for each function call • Values of the parameters • Function’s local variables • Space for result • Where to return to (important if multiple calls!) • For each function call, create a new activation record • For each return, erase the activation record
Writing a string backward • Base case: • Define the problem in terms of a smaller one? • How does each case diminish…? • Guaranteed to reach the base case?
Multiple Calls in One Function • Fibonacci sequence (counting rabbits) • Rabbit(N) = Rabbit(N-1)+Rabbit(N-2) • Rabbit(1) = Rabbit(2) = 1 • (Rabbit is not defined for values < 1)
A Counting Problem • How many ways to visit k of n planets? • Pick some planet (p) • There are count(n-1, k) ways to visit k planets without visiting p • There are count(n-1, k-1) ways to visit k planets with visiting p • Therefore: count(n, k) = count(n-1,k)+count(n-1,k-1) • Base case?
Impractical Recursions • Fibonacci: makes as many calls as rabbits! • Solution: compute it iteratively (save intermediate steps) • Counting: similar to Fibonacci • Solution: use mathematics to come up with a closed form • Count(n,k) = n! / (k! (n-k)!)
Impractical but unavoidable • Towers of Hanoi • Move N disks from one tower to another, never putting a larger disk on a smaller disk • Solution in 3 steps: • Recursively move N-1 disks to the extra tower • Move the Nth disk to the destination tower • Recursively move N-1 disks to the destination tower • Solution time: O(2N)
K’th smallest element • Pick a “partition” element & put smaller elements before, and larger elements after • Remember quicksort? • If “partition” element is k’th, it is the answer • Otherwise, recurse over the half that has the k’th element in it (change k if it’s the second half!) • Impossible to predict how long it will take without knowing the exact array!
Recursive Linked List • The empty list is a linked list • A list consisting of a head item followed by a list of the rest of the items is a linked list • Method to • Add at the beginning of the list • Add at the end of the list • Recursive method to • Count the elements • See if an element is in the list