370 likes | 574 Views
Chapter 14 Recursion. Lecture Slides to Accompany An Introduction to Computer Science Using Java (2nd Edition) by S.N. Kamin, D. Mickunas, , E. Reingold. Chapter Preview. In this chapter we will: introduce recursion as a programming technique
E N D
Chapter 14Recursion Lecture Slides to Accompany An Introduction to Computer Science Using Java (2nd Edition) by S.N. Kamin, D. Mickunas, , E. Reingold
Chapter Preview In this chapter we will: • introduce recursion as a programming technique • show how recursion can be used to simplify the design of complex algorithms • present several well known recursive algorithms (e.g. quicksort, merge sort, Guaussian elmination) • introduce the linked list data structure and recursive implementations for several of its methods • present programs for drawing two types of fractal curves
Recursion • Basic problem solving technique is to divide a problem into smaller subproblems • These subproblems may also be divided into smaller subproblems • When the subproblems are small enough to solve directly the process stops • A recursive algorithm is a problem solution that has been expressed in terms of two or more easier to solve subproblems
Counting Digits • Recursive definition digits(n) = 1 if (–9 <= n <= 9) 1 + digits(n/10) otherwise • Example digits(321) = 1 + digits(321/10) = 1 +digits(32) = 1 + [1 + digits(32/10)] = 1 + [1 + digits(3)] = 1 + [1 + (1)] = 3
Counting Digits in Java int numberofDigits(int n) { if ((-10 < n) && (n < 10)) return 1 else return 1 + numberofDigits(n/10); }
Recursion • If you want to compute f(x) but can’t compute it directly • Assume you can compute f(y) for any value of y smaller than x • Use f(y) to compute f(x) • For this to work, there has to be at least one value of x for which f(x) can be computed directly (e.g. these are called base cases)
static int power(int k, int n) { // raise k to the power n if (n == 0) return 1; else return k * power(k, n – 1); } Evaluating Exponents Recurisivley
Divide and Conquer • Using this method each recursive subproblem is about one-half the size of the original problem • If we could define power so that each subproblem was based on computing kn/2 instead of kn – 1 we could use the divide and conquer principle • Recursive divide and conquer algorithms are often more efficient than iterative algorithms
static int power(int k, int n) { // raise k to the power n if (n == 0) return 1; else{ int t = power(k, n/2); if ((n % 2) == 0) return t * t; else return k * t * t; } Evaluating Exponents Using Divide and Conquer
Selection Sort private static void selectionSort (double[] A, int lo, int hi) { // A[0]..A[lo-1] contain smallest // values in A, in ascending order if (lo < hi) { swap(A, lo, findMiniumum(A, lo, hi); selectionSort(A, lo + 1, hi); } }
Find Minimum private static int findMinimum (double[] A, int lo, int hi) { if (lo == hi) return lo; else { int locationOfMin = findMinimum(A, lo + 1, hi); if (A[lo] < A[locationOfMin]) return lo; else return locationOfMin; } }
Selection Sort Helper Function • Client programs should not need to know anything about how selectionSort was implemented • A single argument helper function can be used to help clients make use of the new version • Example public static void selectionSort(double[] A) { selectionSort(A, 0, A.length – 1); }
Insertion Sort private static void insertionSort (double[] A, int hi) { // Sort A[0] .. A[hi] if (hi > 0) { insertionSort(A, hi – 1); insertInOrder(A, hi, A[hi)); } }
Insert in Order private static void insertInOrder (double[] A, int hi, double x) { // Insert x into A[0]..A[hi-1], // filling in A[hi} in the process. // A[0]..A[hi – 1] are sorted. if ((hi == 0) || (A[hi – 1] <= x)) A[hi] = x; else A[hi] = A[hi – 1]; insertInOrder(A, hi – 1, x); } }
Insertion Sort Helper Function • Again we should provide potential clients with a single argument helper functon public static void InsertionSort(double[] A) { InsertionSort(A, A.length – 1); }
Quicksort Overview • Choose the middle element among A[lo]..A[hi] • Move other elements so that • A[lo]..A[m – 1] are less than A[m] • A[m + 1]..A[hi] are greater than A[m] • Return m to the caller
Quicksort static void quickSort (double[] A, int lo, int hi) { int m; if (hi > lo + 1) { // 3 or more subarray values m = partition(A, lo, hi); quickSort(A, lo, m – 1); quickSort(A, m + 1, hi); } else // less than 3 subarray values if ((hi == lo + 1) && (A[lo] > A[hi]) swap(A, lo, hi); }
Partition static int partition (double[] A, int lo, int hi) { // choose middle element from A[lo}..A[hi] // move elements so A[lo]..A[m-1] are all < A[m] // move elements so A[m+1]..A[hi] are all > A[m] swap(A, lo, medianLocationA, lo+1, hi, (lo+hi)/2)); int m = partition(A, lo+1, hi, A[lo]); swap(A, lo, m); return m; }
Partition Helper static int partition (double[] A, int lo, int hi, double pivot) { if (hi == lo) if (A[lo] < pivot) return lo; else return lo – 1; else if (A[lo] <= pivot) // A[lo] in correct half return partition(A, lo + 1, hi, pivot); else { // A[lo] in wrong half swap(A, lo, hi); return parition(A, lo, hi – 1, pivot); } }
Median Location static int medianLocation (double[] A, int i, int j, int k) { if (A[i] <= A[j]) if (A[j] < A[k]) return j;0 else if (A[i] <= A[k]) return k; else return i; else // A[j] < A[i] if (A[i] <= A[k]) return i; else if (A9j] <= A[k]) return k; else return j; }
Linear Systems a11x1 + a12x2 + … + a1nxn = b1 a11x1 + a12x2 + … + a1nxn = b1 … … … … a11x1 + a12x2 + … + a1nxn = b1
Solving Linear Systems solve (System E of n equations in n unkonwns) { if (n == 1) // system is ax = b return (b/a); else { eliminate last equation yielding system E’; solve(E’), yielding x1, … ,xn-1; xn = (bn – an,1x1 - … - a1,n-2xn-1)/ an,n return (x1, … , xn-1,xn); } }
Integer List Class class IntList { private int value; private IntList tail; public IntList(int v, IntList next) { value = v; tail = next; } public int getValue () { return value; } public intList getTail (){ return Tail; }
Constructing a Linked List • One approach would be: IntList list = new IntList(-14, null); list = new IntList(616, list); list = new IntList(10945, list); list = new IntList(17, list); • Alternatively we could have written: IntList list = new IntList(17, new IntList(616, new IntList(10945, new IntList(17, null))));
Constructing a Linked List from Input Intlist readReverseList () { int inputval; IntList front = null; Inputbox in = new IntputBox(); while (true){ inputval = in.readInt(); if (in.eoi)) break; front = new IntList(inputval, front); } return front; }
Printing Linked List void print (IntList list) { Output out new OutputBox(); while (list != null) { out.print(list.getValue() + “ “); list = list.getTail(); } out.println(); }
Computing List Length • This method would be added to IntList public int length() { if (tail == null) return 1; else return 1 + tail.length(); }
Converting List to String • This method would be added to IntList public String toString() { String myValue = Integer.toString(value); if (tail == null) return myValue; else return myValue + “, “ + tail.toString(); }
Retrieving nth List Element • This method would be added to IntList public IntList nth(int n) { if (n = 0) return this; else if (tail == null) return null; else return tail.nth(n – 1); }
Adding Element to End of List • This method would be added to IntList public void addToEndM(int n) { if (tail != null) // in the middle of the list tail.addToEndM(n); else // at last cell tail = new IntList(n, null); }
Adding Element to List in Order • This method would be added to IntList public IntList addInorderM(int n) { if (n < value) return new IntList(n, this); else if (n == value) return this; if (tail != null){ tail = new IntList(n, null); return this; } else{ tail = tail.addInorderM(n); return this; } }
MergeSort public static IntList mergeSort (IntList L) { // Sort L by recursively splitting and merging if ((L == null) || (L.getTail() == null); // zero or one item return L; else { // two or more items // Split the list into two parts IntListPair p = L.split(); // Sort and merge the two parts return mergeSort(p.x).merge(mergeSort(p.y)); } }
IntListPair class IntListPair { public IntList x, y; public IntListPair (IntList x, IntList y) { this.x = x; this.y = y; } }
Splitting the List • This method would be added to IntListPair public IntList split() { if (tail != null) return = new IntListPair(this, null); else{ IntListPair p = tail.split(); return new IntListPair(new IntList(value,p.y),p.y); } }
Merging the Lista • This method would be added to IntList IntList merge(IntList L) { if (L = null) return this; if (value < L.value) if (tail == null) return new IntList(value, L); else return new IntList(value, tail.merge(L)); return new return new IntList(L.value,merge(L.tail)); } }