Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
COS 312 DAY 22 Tony Gauvin Agenda • Questions? • Last Capstone Progress reports due April 23 • Assignment 6 Over Due and Not corrected – Still 2 MIA • Assignment 7 Posted – Chapters 15, 17 & 18 – Due April 30 – 20 point Bonus Program • Course Evaluations • Iterators • Begin Recursion Ch 1 -2 Final Countdown • Today – Iterators – Begin recursion • April 23 – Recursion – Course Evaluations – Capstone Progress report due Java Foundations, 3rd Edition, Lewis/DePasquale/Chase • April 27 – Searching and sorting • April 30 – Trees – Assignment 7 due • May 4 @ 1 PM – Capstone Presentations – Quiz 3 5-3 Chapter 16 Iterators Chapter Scope • • • • • The purpose of an iterator The Iterator and Interable interfaces The concept of fail-fast collections Using iterators to solve problems Iterator implementations Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 16 - 5 Iterators • Using various methods, the user could write code to access each element in a collection, but it would be slightly different for each collection • An iterator is an object that allows the user to acquire and use each element in a collection • It works with a collection, but is a separate object • An iterator simplifies the classic step of processing elements in a collection Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 16 - 6 Iterators • There are two key interfaces in the Java API related to iterators: – Iterator – used to define an iterator • http://docs.oracle.com/javase/7/docs/api/java/util/Iterator.html – Iterable – used to define a collection that provides an iterator • http://docs.oracle.com/javase/7/docs/api/java/lang/Iterable.html • A collection is Iterable, which means it will provide an Iterator when requested • Example: An Array is Iterable and it provides an Iterator of what ever type was used to construct the array when requested • String[4] provides an Iterator of type String Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 16 - 7 Iterators • The Iterator interface: • The Iterable interface: Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 16 - 8 Iterators • Suppose myList is an ArrayList of Book objects Iterator<Book> itr = myList.iterator(); while (itr.hasNext()) System.out.println(itr.next()); • The first line obtains the iterator, then the loop uses hasNext and next to access and print each book Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 16 - 9 Iterators • A for-each loop can be used for the same goal: for (Book book : myList) System.out.println(book); • The for-each loop uses an iterator behind the scenes (book) • The for-each loop can be used on any object (collection) that is Iterable Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 16 - 10 Iterators • You may want to use an iterator explicitly if you don't want to process all elements – i.e., searching for a particular element • You may also use an explicit iterator if you want to call the remove method • The for-each loop does not give access to the iterator, so remove cannot be called Iterator<Book> itr = myList.iterator(); while (itr.hasNext()) If (itr == “Dune”) itr.remove()); Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 16 - 11 Iterators • You shouldn't assume that an iterator will deliver the elements in any particular order unless the documentation explicitly says you can • Also, remember that an iterator is accessing the elements stored in the collection • The structure of the underlying collection should not be changed while an iterator is being used • Most iterators in the Java API are fail-fast, meaning they throw an exception if the collection is modified while the iterator is active Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 16 - 12 Program of Study Revisited • The ProgramOfStudy class was introduced in the last chapter • It implements the Iterable interface • Its iterator method returns the iterator provided by the list • The POSGrades class uses a for-each loop to print courses with a grade of A or A- Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 16 - 13 import import import import import import import import import import java.io.FileInputStream; java.io.FileNotFoundException; java.io.FileOutputStream; java.io.IOException; java.io.ObjectInputStream; java.io.ObjectOutputStream; java.io.Serializable; java.util.Iterator; java.util.LinkedList; java.util.List; /** * Represents a Program of Study, a list of courses taken and planned, for an * individual student. * * @author Java Foundations * @version 4.0 */ public class ProgramOfStudy implements Iterable<Course>, Serializable { private List<Course> list; /** * Constructs an initially empty Program of Study. */ public ProgramOfStudy() { list = new LinkedList<Course>(); } Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 15 - 14 /** * Adds the specified course to the end of the course list. * * @param course the course to add */ public void addCourse(Course course) { if (course != null) list.add(course); } /** * Finds and returns the course matching the specified prefix and number. * * @param prefix the prefix of the target course * @param number the number of the target course * @return the course, or null if not found */ public Course find(String prefix, int number) { for (Course course : list) if (prefix.equals(course.getPrefix()) && number == course.getNumber()) return course; return null; } Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 15 - 15 /** * Adds the specified course after the target course. Does nothing if * either course is null or if the target is not found. * * @param target the course after which the new course will be added * @param newCourse the course to add */ public void addCourseAfter(Course target, Course newCourse) { if (target == null || newCourse == null) return; int targetIndex = list.indexOf(target); if (targetIndex != -1) list.add(targetIndex + 1, newCourse); } Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 15 - 16 /** * Replaces the specified target course with the new course. Does nothing if * either course is null or if the target is not found. * * @param target the course to be replaced * @param newCourse the new course to add */ public void replace(Course target, Course newCourse) { if (target == null || newCourse == null) return; int targetIndex = list.indexOf(target); if (targetIndex != -1) list.set(targetIndex, newCourse); } /** * Creates and returns a string representation of this Program of Study. * * @return a string representation of the Program of Study */ public String toString() { String result = ""; for (Course course : list) result += course + "\n"; return result; } Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 15 - 17 /** * Returns an iterator for this Program of Study. * * @return an iterator for the Program of Study */ public Iterator<Course> iterator() { return list.iterator(); } /** * Saves a serialized version of this Program of Study to the specified * file name. * * @param fileName the file name under which the POS will be stored * @throws IOException */ public void save(String fileName) throws IOException { FileOutputStream fos = new FileOutputStream(fileName); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(this); oos.flush(); oos.close(); } Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 15 - 18 /** * Loads a serialized Program of Study from the specified file. * * @param fileName the file from which the POS is read * @return the loaded Program of Study * @throws IOException * @throws ClassNotFoundException */ public static ProgramOfStudy load(String fileName) throws IOException, ClassNotFoundException { FileInputStream fis = new FileInputStream(fileName); ObjectInputStream ois = new ObjectInputStream(fis); ProgramOfStudy pos = (ProgramOfStudy) ois.readObject(); ois.close(); return pos; } } Code\chap16\ProgramOfStudy.java Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 15 - 19 import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; /** * Demonstrates the use of an Iterable object (and the technique for reading * a serialzed object from a file). * * @author Java Foundations * @version 4.0 */ public class POSGrades { /** * Reads a serialized Program of Study, then prints all courses in which * a grade of A or A- was earned. */ public static void main(String[] args) throws Exception { ProgramOfStudy pos = ProgramOfStudy.load("ProgramOfStudy"); System.out.println(pos); System.out.println("Classes with Grades of A or A-\n"); for (Course course : pos) { if (course.getGrade().equals("A") || course.getGrade().equals("A-")) System.out.println(course); } } } Code\chap16\POSGrades.java Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 16 - 20 Program of Study Revisited • Now we'll use an iterator to remove any course in the program of study that doesn't already have a grade • Since the iterator's remove method will be used, we cannot use a for-each loop Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 16 - 21 import java.io.FileInputStream; import java.io.ObjectInputStream; import java.util.Iterator; /** * Demonstrates the use of an explicit iterator. * * @author Java Foundations * @version 4.0 */ public class POSClear { /** * Reads a serialized Program of Study, then removes all courses that * don't have a grade. */ public static void main(String[] args) throws Exception { ProgramOfStudy pos = ProgramOfStudy.load("ProgramOfStudy"); System.out.println(pos); System.out.println("Removing courses with no grades.\n"); Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 16 - 22 Iterator<Course> itr = pos.iterator(); while (itr.hasNext()) { Course course = itr.next(); if (!course.taken()) itr.remove(); } System.out.println(pos); pos.save("ProgramOfStudy"); } } Code\chap16\POSClear.java Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 16 - 23 Implementing Array-based Iterators • Our ArrayList class contains a private inner class that defines an iterator for the list • An iterator is an appropriate use for an inner class because of its intimate relationship with the outer class (the collection) • It maintains a modification count that is initialized to the current number of elements in the collection • If those counts get out of a sync, the iterator throws a ConcurrentModificationException Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 16 - 24 /** * ArrayListIterator iterator over the elements of an ArrayList. */ private class ArrayListIterator implements Iterator<T> { int iteratorModCount; int current; /** * Sets up this iterator using the specified modCount. * * @param modCount the current modification count for the ArrayList */ public ArrayListIterator() { iteratorModCount = modCount; current = 0; } Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 16 - 25 /** * Returns true if this iterator has at least one more element * to deliver in the iteration. * * @return true if this iterator has at least one more element to deliver * in the iteration * @throws ConcurrentModificationException if the collection has changed * while the iterator is in use */ public boolean hasNext() throws ConcurrentModificationException { if (iteratorModCount != modCount) throw new ConcurrentModificationException(); return (current < rear); } Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 16 - 26 /** * Returns the next element in the iteration. If there are no * more elements in this iteration, a NoSuchElementException is * thrown. * * @return the next element in the iteration * @throws NoSuchElementException if an element not found exception occurs * @throws ConcurrentModificationException if the collection has changed */ public T next() throws ConcurrentModificationException { if (!hasNext()) throw new NoSuchElementException(); current++; return list[current - 1]; } Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 16 - 27 /** * The remove operation is not supported in this collection. * * @throws UnsupportedOperationException if the remove method is called */ public void remove() throws UnsupportedOperationException { throw new UnsupportedOperationException(); } } } Code\chap16\jsjf\ArrayList.java Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 16 - 28 Implementing Linked-Based Iterators • Similarly, an iterator can use links • Like the previous example, the LinkedListItertor class is implemented as a private inner class Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 16 - 29 /** * LinkedIterator represents an iterator for a linked list of linear nodes. */ private class LinkedListIterator implements Iterator<T> { private int iteratorModCount; // the number of elements in the collection private LinearNode<T> current; // the current position /** * Sets up this iterator using the specified items. * * @param collection the collection the iterator will move over * @param size the integer size of the collection */ public LinkedListIterator() { current = head; iteratorModCount = modCount; } Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 16 - 30 /** * Returns true if this iterator has at least one more element * to deliver in the iteration. * * @return true if this iterator has at least one more element to deliver * in the iteration * @throws ConcurrentModificationException if the collection has changed * while the iterator is in use */ public boolean hasNext() throws ConcurrentModificationException { if (iteratorModCount != modCount) throw new ConcurrentModificationException(); return (current != null); } Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 16 - 31 /** * Returns the next element in the iteration. If there are no * more elements in this iteration, a NoSuchElementException is * thrown. * * @return the next element in the iteration * @throws NoSuchElementException if the iterator is empty */ public T next() throws ConcurrentModificationException { if (!hasNext()) throw new NoSuchElementException(); T result = current.getElement(); current = current.getNext(); return result; } Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 16 - 32 /** * The remove operation is not supported. * * @throws UnsupportedOperationException if the remove operation is called */ public void remove() throws UnsupportedOperationException { throw new UnsupportedOperationException(); } } } Code\chap16\jsjf\LinkedList.java Code\chap16\OrderedLLTester.java Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 16 - 33 Chapter 17 Recursion Chapter Scope • • • • • The concept of recursion Recursive methods Infinite recursion When to use (and not use) recursion Using recursion to solve problems – Solving a maze – Towers of Hanoi Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 35 Recursion • Recursion is a programming technique in which a method can call itself to fulfill its purpose • A recursive definition is one which uses the word or concept being defined in the definition itself • In some situations, a recursive definition can be an appropriate way to express a concept • Before applying recursion to programming, it is best to practice thinking recursively Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 36 Recursive Definitions • Consider the following list of numbers: 24, 88, 40, 37 • Such a list can be defined recursively: A LIST is a: or a: number number comma LIST • That is, a LIST can be a number, or a number followed by a comma followed by a LIST • The concept of a LIST is used to define itself Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 37 Recursive Definitions LIST: number comma LIST 24 , 88, 40, 37 number comma LIST 88 , 40, 37 number comma LIST 40 , 37 number 37 Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 38 Other Recursive Definitions • Recursive acronym – GNU GNU’s Not UNIX • Definitions in Nature – A fern is a fern to the front, a fern to the left and a fern to the right • Number series 10, 15, 20, 25, 30, 35 …. a1 = 10; an = an-1 + 5 Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 5 - 39 Infinite Recursion • All recursive definitions must have a nonrecursive part (termination or base-case) • If they don't, there is no way to terminate the recursive path • A definition without a non-recursive part causes infinite recursion • This problem is similar to an infinite loop -- with the definition itself causing the infinite “looping” • The non-recursive part is called the base case Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 40 Recursion in Math • Mathematical formulas are often expressed recursively • N!, for any positive integer N, is defined to be the product of all integers between 1 and N inclusive • This definition can be expressed recursively: 1! N! = = 1 N * (N-1)! • A factorial is defined in terms of another factorial until the base case of 1! is reached Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 41 Recursive Programming • A method in Java can invoke itself; if set up that way, it is called a recursive method • The code of a recursive method must handle both the base case and the recursive case • Each call sets up a new execution environment, with new parameters and new local variables • As always, when the method completes, control returns to the method that invoked it (which may be another instance of itself) Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 42 Recursive Programming • Consider the problem of computing the sum of all the integers between 1 and N, inclusive • If N is 5, the sum is 1+2+3+4+5 • This problem can be expressed recursively as: The sum of 1 to N is N plus the sum of 1 to N-1 Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 43 Recursive Programming • The sum of the integers between 1 and N: Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 44 Recursive Programming • A recursive method that computes the sum of 1 to N: public int sum(int num) { int result; if (num == 1) result = 1; //base-case else result = num + sum(num-1); //recursive step return result; } Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 45 Recursive Programming • Tracing the recursive calls of the sum method Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 46 Recursion vs. Iteration • Just because we can use recursion to solve a problem, doesn't mean we should • For instance, we usually would not use recursion to solve the sum of 1 to N • The iterative version is easier to understand (in fact there is a formula that computes it without a loop at all) • You must be able to determine when recursion is the correct technique to use Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 47 Recursion vs. Iteration • Every recursive solution has a corresponding iterative solution • A recursive solution may simply be less efficient • Furthermore, recursion has the overhead of multiple method invocations • However, for some problems recursive solutions are often more simple and elegant to express Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 48 Direct vs. Indirect Recursion • A method invoking itself is considered to be direct recursion • A method could invoke another method, which invokes another, etc., until eventually the original method is invoked again • For example, method m1 could invoke m2, which invokes m3, which invokes m1 again • This is called indirect recursion • It is often more difficult to trace and debug Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 49 Direct vs. Indirect Recursion Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 50 Maze Traversal • We've seen a maze solved using a stack • The same approach can also be done using recursion • The run-time stack tracking method execution performs the same function • As before, we mark a location as "visited" and try to continue along the path • The base cases are: – a blocked path – finding a solution Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 51 Maze Traversal Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 52 import java.util.*; import java.io.*; /** * MazeTester uses recursion to determine if a maze can be traversed. * * @author Java Foundations * @version 4.0 */ public class MazeTester { /** * Creates a new maze, prints its original form, attempts to * solve it, and prints out its final form. */ public static void main(String[] args) throws FileNotFoundException { Scanner scan = new Scanner(System.in); System.out.print("Enter the name of the file containing the maze: "); String filename = scan.nextLine(); Maze labyrinth = new Maze(filename); System.out.println(labyrinth); MazeSolver solver = new MazeSolver(labyrinth); Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 53 if (solver.traverse(0, 0)) System.out.println("The maze was successfully traversed!"); else System.out.println("There is no possible path."); System.out.println(labyrinth); } } Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 54 import java.util.*; import java.io.*; /** * Maze represents a maze of characters. The goal is to get from the * top left corner to the bottom right, following a path of 1's. Arbitrary * constants are used to represent locations in the maze that have been TRIED * and that are part of the solution PATH. * * @author Java Foundations * @version 4.0 */ public class Maze { private static final int TRIED = 2; private static final int PATH = 3; private int numberRows, numberColumns; private int[][] grid; Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 55 /** * Constructor for the Maze class. Loads a maze from the given file. * Throws a FileNotFoundException if the given file is not found. * * @param filename the name of the file to load * @throws FileNotFoundException if the given file is not found */ public Maze(String filename) throws FileNotFoundException { Scanner scan = new Scanner(new File(filename)); numberRows = scan.nextInt(); numberColumns = scan.nextInt(); grid = new int[numberRows][numberColumns]; for (int i = 0; i < numberRows; i++) for (int j = 0; j < numberColumns; j++) grid[i][j] = scan.nextInt(); } /** * Marks the specified position in the maze as TRIED * * @param row the index of the row to try * @param col the index of the column to try */ public void tryPosition(int row, int col) { grid[row][col] = TRIED; } Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 56 /** * Return the number of rows in this maze * * @return the number of rows in this maze */ public int getRows() { return grid.length; } /** * Return the number of columns in this maze * * @return the number of columns in this maze */ public int getColumns() { return grid[0].length; } /** * Marks a given position in the maze as part of the PATH * * @param row the index of the row to mark as part of the PATH * @param col the index of the column to mark as part of the PATH */ public void markPath(int row, int col) { grid[row][col] = PATH; } Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 57 /** * Determines if a specific location is valid. A valid location * is one that is on the grid, is not blocked, and has not been TRIED. * * @param row the row to be checked * @param column the column to be checked * @return true if the location is valid */ public boolean validPosition(int row, int column) { boolean result = false; // check if cell is in the bounds of the matrix if (row >= 0 && row < grid.length && column >= 0 && column < grid[row].length) // check if cell is not blocked and not previously tried if (grid[row][column] == 1) result = true; return result; } Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 58 /** * Returns the maze as a string. * * @return a string representation of the maze */ public String toString() { String result = "\n"; for (int row=0; row < grid.length; row++) { for (int column=0; column < grid[row].length; column++) result += grid[row][column] + ""; result += "\n"; } return result; } } Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 59 /** * MazeSolver attempts to recursively traverse a Maze. The goal is to get from the * given starting position to the bottom right, following a path of 1's. Arbitrary * constants are used to represent locations in the maze that have been TRIED * and that are part of the solution PATH. * * @author Java Foundations * @version 4.0 */ public class MazeSolver { private Maze maze; /** * Constructor for the MazeSolver class. */ public MazeSolver(Maze maze) { this.maze = maze; } Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 60 /** * Attempts to recursively traverse the maze. Inserts special * characters indicating locations that have been TRIED and that * eventually become part of the solution PATH. * * @param row row index of current location * @param column column index of current location * @return true if the maze has been solved */ public boolean traverse(int row, int column) { boolean done = false; if (maze.validPosition(row, column)) { maze.tryPosition(row, column); // mark this cell as tried if (row == maze.getRows()-1 && column == maze.getColumns()-1) done = true; // the maze is solved else { done = traverse(row+1, column); // down if (!done) done = traverse(row, column+1); // right Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 61 if (!done) done = traverse(row-1, column); if (!done) done = traverse(row, column-1); // up // left } if (done) // this location is part of the final path maze.markPath(row, column); } return done; } } Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 62 The Towers of Hanoi • The Towers of Hanoi is a puzzle made up of three vertical pegs and several disks that slide onto the pegs • The disks are of varying size, initially placed on one peg with the largest disk on the bottom and increasingly smaller disks on top • The goal is to move all of the disks from one peg to another following these rules: – Only one disk can be moved at a time – A disk cannot be placed on top of a smaller disk – All disks must be on some peg (except for the one in transit) Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 63 Towers of Hanoi • The initial state of the Towers of Hanoi puzzle: Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 64 Towers of Hanoi • A solution to the three-disk Towers of Hanoi puzzle: Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 65 Towers of Hanoi • A solution to ToH can be expressed recursively • To move N disks from the original peg to the destination peg: – Move the topmost N-1 disks from the original peg to the extra peg – Move the largest disk from the original peg to the destination peg – Move the N-1 disks from the extra peg to the destination peg • The base case occurs when a peg contains only one disk Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 66 Towers of Hanoi • The number of moves increases exponentially as the number of disks increases • The recursive solution is simple and elegant to express and program, but is very inefficient • However, an iterative solution to this problem is much more complex to define and program Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 67 Towers of Hanoi Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 68 /** * SolveTowers uses recursion to solve the Towers of Hanoi puzzle. * * @author Java Foundations * @version 4.0 */ public class SolveTowers { /** * Creates a TowersOfHanoi puzzle and solves it. */ public static void main(String[] args) { TowersOfHanoi towers = new TowersOfHanoi(4); towers.solve(); } } Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 69 /** * TowersOfHanoi represents the classic Towers of Hanoi puzzle. * * @author Java Foundations * @version 4.0 */ public class TowersOfHanoi { private int totalDisks; /** * Sets up the puzzle with the specified number of disks. * * @param disks the number of disks */ public TowersOfHanoi(int disks) { totalDisks = disks; } /** * Performs the initial call to moveTower to solve the puzzle. * Moves the disks from tower 1 to tower 3 using tower 2. */ public void solve() { moveTower(totalDisks, 1, 3, 2); } Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 70 /** * Moves the specified number of disks from one tower to another * by moving a subtower of n-1 disks out of the way, moving one * disk, then moving the subtower back. Base case of 1 disk. * * @param numDisks the number of disks to move * @param start the starting tower * @param end the ending tower * @param temp the temporary tower */ private void moveTower(int numDisks, int start, int end, int temp) { if (numDisks == 1) moveOneDisk(start, end); else { moveTower(numDisks-1, start, temp, end); moveOneDisk(start, end); moveTower(numDisks-1, temp, end, start); } } Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 71 /** * Prints instructions to move one disk from the specified start * tower to the specified end tower. * * @param start the starting tower * @param end the ending tower */ private void moveOneDisk(int start, int end) { System.out.println("Move one disk from " + start + " to " + end); } } Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 72 Analyzing Recursive Algorithms • To determine the order of a loop, we determined the order of the body of the loop multiplied by the number of loop executions • Similarly, to determine the order of a recursive method, we determine the the order of the body of the method multiplied by the number of times the recursive method is called • In our recursive solution to compute the sum of integers from 1 to N, the method is invoked N times and the method itself is O(1) • So the order of the overall solution is O(n) Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 73 Analyzing Recursive Algorithms • For the Towers of Hanoi puzzle, the step of moving one disk is O(1) • But each call results in calling itself twice more, so for N > 1, the growth function is f(n) = 2n – 1 • This is exponential efficiency: O(2n) • As the number of disks increases, the number of required moves increases exponentially Java Foundations, 3rd Edition, Lewis/DePasquale/Chase 17 - 74