Presentation is loading. Please wait.

# 3/25/2017 Chapter 16 Recursion.

## Presentation on theme: "3/25/2017 Chapter 16 Recursion."— Presentation transcript:

3/25/2017 Chapter 16 Recursion

This chapter discusses
Recursion. Comparison of recursion and iteration. Recursive solutions using class structure, rather than algorithm design to control recursion.

Iteration and recursion
In iteration, the algorithm specifies a step in the solution process that is to be repeated or iterated. Recursion involves providing a solution to a trivial, base case of the problem, and then designing a solution to the general case by showing how to “reduce” the general case to one that is a step closer to the base case; the algorithm invokes itself to solve the “slightly reduced” case.

Recursion

Recursive selection sort
Base Case: sort a list that is empty or contains only a single element. General Case: sort a list containing n elements, where n > 1. Find the smallest element and put it first. Sort the remaining n-1elements. (This is done by invoking the method itself.) These “self-calls” continue until the base case is reached.

Selection Sort private void sort (List list, int
first, int last, Order compare){ int small // index of smallest if (last > first) { small = smallestOf(list, first, last, compare); interchange(list, first, small); sort(list, first+1,last,compare); }

Verification of correctness
Use induction. The base cases of the induction match the base cases of the algorithm. The general case of the induction handles the general case of the algorithm.

Selection Sort

Selection Sort (cont.)

Selection Sort (cont.) We now have two sets of local variables – one for each invocation of the method sort. This is like invoking two different methods; the fact that they happen to be invocations of the same method is irrelevant.

Selection Sort (cont.)

Selection Sort (cont.)

Selection Sort (cont.)

Selection Sort (cont.)

Selection Sort (cont.)

Putting this procedure into a Sorter
Provide a public method that calls the recursive method with the appropriate arguments. public class RecursiveSelectionSorter implements Sorter { public void sort (List list, Order compare) { sort(list,0,list.size()-1,compare); } private void sort (List list, int first, int last, Order compare) {…} private int smallestOf (List list, int first, int last, Order compare) {…} private void interchange (list list, int i, int j) {…} }//end of class RecursiveSelectionSorter

Putting this procedure into a Sorter (cont.)
The method name sort is overloaded. One sort defines the public interface. The other sort is a private "auxiliary" method that does the work.

Towers of Hanoi Move the stack of disks from the starting peg to one of the other pegs, moving only one disk at a time, and without placing a larger disk on top of a smaller disk.

Towers of Hanoi (cont.) We model a move as a class instance.
A move is characterized by the peg a disk is moved from and the peg the disk is moved to.

Recursive algorithm for Towers of Hanoi
Base Case: Only one disk to move. General Case: Move a stack of n disks, where n > 1. Moving n-1 disks is a step closer to the base case. We can ignore the largest disk when considering the n-1 smaller disks.

Recursive algorithm for Towers of Hanoi (cont.)
Move n-1 disks from the starting peg to the “other” peg. Move a disk from the starting peg to the destination peg. Move n-1 disks from the “other” peg to the destination peg.

Recursive algorithm for Towers of Hanoi (cont.)
The client-server relationship is as follows:

Recursive algorithm for Towers of Hanoi (cont.)
public class Move A move in the Towers puzzle. Pegs are numbered 1,2,3. public Move (int from, int to) A move of a disk from “from” to “to”. public int from () Peg the disk is moved from. public int to () Peg the disk is moved to.

Recursive algorithm for Towers of Hanoi (cont.)
public void moveTower (int n, int from, int to, SolverObserver o) Report to the specified observer the moves required to move a tower of the specified number of disks, from the specified starting peg to the specified destination peg. require: n >= 1 1 <= from <= 3 && 1 <= to <= 3 from != to public void update (Move m)

Recursive algorithm for Towers of Hanoi (cont.)
public void moveTower (int n, int from, int to, SolverObserver o) if (n==1) { o.update(new Move(from,to)); } else { int other = 6-from-to //peg that //is not from or to //move n-1 disks to other peg moveTower(n-1,from, other,o); //move big disk to the target //move n-1 disks to the target moveTower(n-1,other,to,o); }

Example: moveDisk(2,1,2,this)

Quick sort Quick sort typically take on the order of n·log2n steps.
n n2 n·log2n , 1,000 1,000,000 9,966 10, ,000, ,877 100,000 10,000,000,000 1,660,964 1,000,000 1,000,000,000,000 19,931,569 Quick sort starts by putting one element into position. Rather than positioning the largest or smallest element, quick sort puts an arbitrary element in proper position.

Quick sort (cont.) 1. Put an element in its proper sorted position, with smaller elements below an larger elements above. The positioned element is the “pivot” element. 2. Sort the sub-list of smaller elements below the positioned element. 3. Sort the sub-list of larger elements above the positioned element. This is clearly recursive!

Quick sort (cont.) public class QuickSorter extends Sorter { /**
* Sort specified List according to the * specified Order, using quick sort. */ public void sort (List list, Order compare) sort(list, 0,list.size()-1,compare); } * Sort list elements first to last private void sort (List list, int first, int last, Order Compare) {

Quick sort (cont.) Base case: an empty list or a list with a single element. General Case: handled by the 3 steps mentioned earlier. We separate step 1 out into its own method called partition. partition changes the state of the list like a command, and returns a value like a query.

Quick sort (cont.) public int partition (List list, int first, int last, Order compare) Partition list elements indexed first through last for quick sort; return the pivot position. require: 0 <= first < last < list.size() ensure: first <= result <= last for first <= i < result, list.get(i) < list.get(result) for result <= i <= last, list,get(i) >= list.get(result)

Quick sort (cont.) Suppose we chose to put 28 in its proper position.
The method returns value 6, the index of the “pivot” element.

Quick sort (cont.) private void sort (List list, int
first, int last, Order compare) { int position; //the pivot index if(first < last) { position = partition(list,first, last,compare); sort(list,first,positions-1,compare); sort(list,position+1,last,compare); }

Quick sort (cont.)

Quick sort (cont.)

Quick sort (cont.)

Quick sort (cont.)

Quick sort (cont.)

Quick sort (cont.)

Quick sort (cont.)

Quick sort (cont.)

Quick sort (cont.)

Quick sort (cont.) private int partition (List list, int first, int last, Order compare) { int pi; //pivot index; int i; //next item of 1 to examine int mid; //middle index: (first+last)/2 Object item; // pivot item mid = (first+last)/2; item = list.get(mid); //put pivot item at end of list interchange(list,mid,last); pi = first; i = first; //haven’t examined anything //yes=t

Quick sort (cont.) /* loop invariant: * for first <= j <pi
* list.get(j) < item * for pi <= j < i * list.get(j) >= item */ while (i != last) { //last is pivot index if (compare.lessThan(list.get(i),item)) { interchange(list,pi,i) pi = pi+1; } i = i+1; interchange(list,pi,last); //put pivot item //in place return pi;

Quick sort (cont.) When the while loop is reached for the first time, the clauses of the invariant are vacuously true. Since first == pi == I, there is no value j such that first <= j <= pi and there is no value j such that pi <= j < I. We select the middle item because in the worst case, the algorithm could take order n2 time. If the list is ordered (or nearly ordered) and we chose the first or last elements in the list, the order is closer to n2 .

Inefficiency It is often more difficult to design recursive algorithms that are as efficient as iterative algorithms. Since we control the steps in an iterative process more directly than in a recursive process, inefficiencies often are more obvious in an iterative algorithm.

Fibonacci numbers The sequence of integers beginning with 0 and 1, and in which each successive number is the sum of the previous two: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34… public int fib (int n) { if (n ==0) return 0; else if (n == 1) return 1; else return fib(n-1)+fib(n-2) }

Fibonacci numbers (cont.)
Each level of recursion duplicates work done at the previous level. Example: computing fib(6) requires computing fib(5) and fib(4), but the computation of fib(5) also computes fib(4). The time to compute fib(n) is roughly proportional to fib(n)! An iterative approach solves the problem in computational time proportional to n.

Indirect recursion A method can invoke itself indirectly.
m1 invokes m2 which invokes m3… which invokes mn which invokes m1.

Heads or Tails public char head (String s)
The first character of the specified non-empty String. public String tail (String s) A String equal to the specified non-empty String with its first character removed. head(“abc”)  ‘a’ tail(“abc”)  “bc”

Balanced Parentheses A function that removes the first balanced substring of parentheses. “()”  “” “()()()()”  “()()()” “((()))”  “” “(()()(()()))()(())”  “()(())”

Balanced Parentheses (cont.)
public String removeSet (String s) A String equal to the specified String with the first balanced substring of parentheses removed require: s is a balanced string of parentheses private String reduceClosed (String s) A String equal to the specified String with the first substring containing one more closed parenthesis than open parentheses removed. s is a string of parentheses that would be balanced if an open parenthesis were appended to the front; in particular, s contains one more closed parenthesis than open parentheses.

Balanced Parenthesis (cont.)
public String removeSet (String s) { if (s.equals(“”)) return “”; else // head(s) is ‘(‘ return reduceClosed(tail(s)); } private String reduceClosed (String s) { if ( head(s) == ‘)’ ) return tail(s); //head(s) == ‘(‘;first remove a balanced set. return reduceClosed(removeSet(s));

Object recursion Structural recursion: using object structure in a recursive manner to derive problem solutions. An object tasked with solving a problem gets assistance from a similar object which solves a simpler instance of the problem.

Object recursion (cont.)

Odometer A sequence of digits, in which one digit “turning over” from 9 to 0 causes its left neighbor to increment. A “solution state” is a stable state of the counter, in which all the digits are set. In the first solution state, all digits are 0. A next solution state is reached when the counter is incremented by 1. In the final solution state, all digits are 9.

Odometer (cont.) The solver class is Digit.
The trivial solver class is NullDigit. Each Digit is responsible for a digit of the solution.

Odometer (cont.) Each Digit has an associate, the Digit to its left.
A Digit “extends” the solution provided by its associate; a four-digit number, for example, is built by extending a three-digit number. The right-most Digit in a 1-digit number has a NullDigit associate.

Odometer (cont.)

Odometer (cont.) An inner class is a class defined inside another class. We make AbstractDigit, Digit, and NullDigit inner classes of the DigitCounter.

public class DigitCounter {
/** * Create a new DigitCounter with the specified number of digits. * require: * digits >= 1 */ public DigitCounter (int digits) { int i; AbstractDigit d = new NullDigit(); for (i = 1; i <= digits; i = i+1) d = new Digit(d); lowDigit = d; } private AbstractDigit lowDigit;//right most private abstract class AbstractDigit{…} private class NullDigit extends AbstractDigit{…} private class Digit extends AbstractDigit{ private Digit(AbstractDigit associate) { this.associate = associate; … } … private AbstractDigit associate;//left //neighbor

Odometer (cont.) command: solved: toString: -- false -- first true 00
next true next true next true next false

public class DigitCounter { …
/** * Set to all zeros. */ public void first() { lowDigit.first(); } * Increment this DigitCounter by 1 public void next () { lowDigit.next(); * First or next has been sucessfully performed public boolean solved() { return lowDigit.solved(); * Number contained in this DigitCounter * require: * this.solved() public String toString() { return lowDigit.toString();

private AbstractDigit lowDigit;//right-most
private abstract class AbstractDigit { public abstract boolean solved (); public abstract void first(); public abstract void next(); public abstract String toString(); }

private class Digit extends AbstractDigit {
public Digit (AbstractDigit associate) { this.associate = associate; this.digit = 0; this.solved = false; } public boolean solved () { return solved; public void first () { associate.first(); if (associate.solved()) { digit = 0; solved = true; } else solved = false;

public void next () { if (digit < 9) { digit = digit + 1; solved = true; } else { associate.next(); if (associate.solved()) { digit = 0; } else solved = false; } public String toString () { return associate.toString() + digit; public AbstractDigit associate () { return associate; private AbstractDigit associate;//left //neighbor private boolean solved; //a valid number private int digit; //my digit

private class NullDigit extends AbstractDigit {
public boolean solved () { return solved; } public void first () { solved = true; public void next () { solved = false; public String toString () { return “”; private boolean solved; Class NullDigit permits all object entries in the structure to be treated uniformly.

We’ve covered Recursive computation Indirect recursion
Algorithmic recursion Object recursion Indirect recursion Structural recursion

Glossary

Similar presentations

Ads by Google