Chapter 14 Recursion Lecture Slides to Accompany An Introduction to Computer Science Using Java (2nd...

Preview:

Citation preview

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 • 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 definitiondigits(n) = 1 if (–9 <= n <= 9)

1 + digits(n/10) otherwise

• Exampledigits(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)

Evaluating Exponents Recurisivley

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);

}

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

Evaluating Exponents Using Divide and Conquer

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;}

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 Minimumprivate 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

• Examplepublic 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 Locationstatic 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 IntListpublic 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 IntListpublic 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 IntListIntList 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));

}

}

Recommended