Download COS312Day22 - Ecom and COS classes

Document related concepts
no text concepts found
Transcript
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