/* maintain a database of taxpayers and the tax for each
* @author Biagioni, Edoardo
* @assignment lecture 18
* @date March 14, 2008
* @bugs no error message if you remove a record not in the database
* @inspiration William Albritton's Menu.java,
* http://www2.hawaii.edu/~walbritt/ics211/treeBinarySearch/Menu.java
* @inspiration ShoppingMenu.java
* http://www2.ics.hawaii.edu/~esb/2008spring.ics211/ShoppingMenu.java.html
*/
import javax.swing.*;
import java.util.NoSuchElementException;
import java.util.Scanner;
import java.util.Iterator;
import java.util.regex.*;
import java.io.File;
import java.io.FileWriter;
import java.util.Stack;
public class ChengJade08 {
final static String databaseName = "database.csv";
/* do nothing, data fields are already initialized */
public ChengJade08() {
}
/* main method is invoked when the program is started
* @param arguments if a single command-line argument is given, it is
* the name of the file containing the database
*/
public static void main(String [] arguments) {
String thisDatabaseName = databaseName;
if (arguments.length == 1) {
thisDatabaseName = arguments[0];
}
BinarySearchTree<Taxpayer> database = null;
database = readFromDatabase(thisDatabaseName);
while (executeMenu(database)) {
// after every non-exit command, save to the database
saveToDatabase(database, thisDatabaseName);
}
System.exit(0);
}
/* @param database reference to a database of taxpayers
* @return whether to continue execution
*/
private static boolean executeMenu(BinarySearchTree<Taxpayer> db) {
String[] choices = { "add a new taxpayer record",
"change tax for a taxpayer",
"remove a taxpayer record",
"display the database", "find the previous record",
"find the next record", "exit program" };
// ask the user to tell us what they want to do
int choice =
JOptionPane.showOptionDialog(null, "please enter", "taxpayers",
JOptionPane.DEFAULT_OPTION,
JOptionPane.QUESTION_MESSAGE,
null, choices, -1);
switch(choice) {
case 0:
addNewRecord(db);
break;
case 1:
changeTax(db);
break;
case 2:
removeRecord(db);
break;
case 3:
System.out.println(db.toString());
break;
//----------------------------------------------------------------------------//
case 4:
System.out.println(findPreviousRecord(db));
break;
case 5:
System.out.println(findNextRecord(db));
break;
//----------------------------------------------------------------------------//
// case 6: handled below
}
// whatever we did is done, save the database and return
return (choice != (choices.length - 1));
}
/* read a database from a file
* @return database read from a file, or throws exception
*/
private static BinarySearchTree<Taxpayer> readFromDatabase(String file) {
BinarySearchTree<Taxpayer> db = new BinarySearchTree<Taxpayer>();
int readSuccessfully = 0;
try {
// database is assumed to be a sequence of lines, one item per line
File dbFile = new File(file);
Scanner dbRead = new Scanner(dbFile);
while (dbRead.hasNextLine()) {
String line = dbRead.nextLine();
Scanner lineScan = new Scanner(line);
// the record is comma-separated
lineScan.useDelimiter(",");
// each line should have the taxpayer name, followed
// by the SSN, followed by the tax, all separated by commas
// e.g. "Foo Bar,123456789,-3124.37
String taxpayer = lineScan.next();
// read the social security number
int SSN = lineScan.nextInt();
// read the tax
double tax = lineScan.nextDouble();
db.add(new Taxpayer(taxpayer, SSN, tax));
readSuccessfully++;
}
} catch (Exception e) {
if (readSuccessfully > 0) {
System.out.println("error " + e +
" reading database after reading " +
readSuccessfully + " entries");
} else {
System.out.println("error " + e + " reading database " +
file + "\nstarting with empty database");
}
}
return db;
}
/* @param database to save to the file
*/
private static void saveToDatabase(BinarySearchTree<Taxpayer> db,
String name) {
try {
// preorder traversal, so the same tree is built again
// when we read it back
Iterator<Taxpayer> it = db.preIterator();
FileWriter out = new FileWriter(name);
while (it.hasNext()) {
Taxpayer record = it.next();
out.write(record.getName() + "," + record.getSSN() + "," +
record.getTax() + "\n");
}
out.close();
} catch (Exception e) {
/* this is an error. Notify the user */
String message = "unable to save to file " + name;
JOptionPane.showMessageDialog(null, message);
}
}
/* get a taxpayer record from the user, save it in the database
* @param db to which the item is added
*/
private static void addNewRecord(BinarySearchTree<Taxpayer> db) {
final String prompt1 = "enter taxpayer name";
String name = JOptionPane.showInputDialog(null, prompt1);
if (name != null) { // null name if canceled
final String prompt2 = "enter SSN for taxpayer " + name;
Integer SSN = getUserInteger(prompt2);
if (SSN != null) { // null string means not a valid number
final String prompt3 = "enter amount of tax for " + name;
Double tax = getUserDouble(prompt3);
db.add(new Taxpayer(name, SSN, tax));
}
}
}
/* change the tax for a taxpayer in the database
* @param db in which the taxpayer record is changed
*/
private static void changeTax(BinarySearchTree<Taxpayer> db) {
final String prompt1 = "enter SSN of taxpayer";
Integer SSN = getUserInteger(prompt1);
if (SSN != null) { // null string means not a valid number
// build a key, that is, a taxpayer where only the SSN is valid
Taxpayer key = new Taxpayer(SSN);
Taxpayer record = db.get(key);
if (record == null) { // not in database, cannot change tax
JOptionPane.showMessageDialog(null,
"social security number " + SSN +
" not found in database");
} else { // is in database, get the new tax amount
final String prompt2 = "enter amount of tax for " +
record.getName();
Double tax = getUserDouble(prompt2);
record.setTax(tax);
// this addition should replace the original record
db.add(record);
}
}
}
/* remove a taxpayer from the database given the social security number
* @param db from which the taxpayer record is removed
*/
private static void removeRecord(BinarySearchTree<Taxpayer> db) {
final String prompt = "enter SSN of taxpayer to remove from database";
Integer SSN = getUserInteger(prompt);
if (SSN != null) { // null string means not a valid number
// build a key, that is, a taxpayer where only the SSN is valid
Taxpayer key = new Taxpayer(SSN);
db.remove(key);
}
}
//----------------------------------------------------------------------------//
/**
* finds a previous record in a taxpayer database based on user input
*
* @param db the taxpayer database
* @return a message containing the previous record if one exists
*/
private static String findPreviousRecord(BinarySearchTree<Taxpayer> db) {
final String prompt1 = "enter SSN of taxpayer";
final Integer SSN = getUserInteger(prompt1);
if (SSN == null) // null SSN if canceled
return "operation canceled";
final Taxpayer key = new Taxpayer(SSN.intValue());
try {
final Taxpayer entry = db.findPrevious(key);
if (entry == null) // null entry means no matching key
return "no matching record for SSN " + SSN;
return "previous record for SSN " + SSN + ": --> " + entry;
} catch (NoSuchElementException e) {
// error indicates key is found but no previous record
return "no previous record for SSN " + SSN;
}
}
/**
* finds a next record in a taxpayer database based on user input
*
* @param db the taxpayer database
* @return a message containing the next record if one exists
*/
private static String findNextRecord(BinarySearchTree<Taxpayer> db) {
final String prompt1 = "enter SSN of taxpayer";
final Integer SSN = getUserInteger(prompt1);
if (SSN == null) // null SSN if canceled
return "operation canceled";
final Taxpayer key = new Taxpayer(SSN.intValue());
try {
final Taxpayer entry = db.findNext(key);
if (entry == null) // null entry means no matching key
return "no matching record for SSN " + SSN;
return "next record for SSN " + SSN + ": --> " + entry;
} catch (NoSuchElementException e) {
// error indicates key is found but no next record
return "no next record for SSN " + SSN;
}
}
// ----------------------------------------------------------------------------//
/* @param prompt for the user
* @return null, or the integer the user entered
*/
private static Integer getUserInteger(String prompt) {
String userChoice = JOptionPane.showInputDialog(null, prompt);
if (userChoice == null) { // cancel returns a null string
return null;
}
Scanner scan = new Scanner(userChoice);
if (! scan.hasNextInt()) { // might not be an int
JOptionPane.showMessageDialog(null, "did not enter a number");
return null;
}
Integer choice = scan.nextInt();
return choice;
}
/* @param prompt for the user
* @return null, or the double the user entered
*/
private static Double getUserDouble(String prompt) {
String userChoice = JOptionPane.showInputDialog(null, prompt);
if (userChoice == null) { // cancel returns a null string
return null;
}
Scanner scan = new Scanner(userChoice);
if (! scan.hasNextDouble()) { // might not be a double
JOptionPane.showMessageDialog(null, "did not enter a number");
return null;
}
return scan.nextDouble();
}
}
/* a class for binary tree nodes
* @author Biagioni, Edoardo
* @assignment lecture 17
* @date March 12, 2008
* @inspiration William Albritton's binary search tree class,
http://www2.hawaii.edu/~walbritt/ics211/treeBinarySearch/BinarySearchTree.java
*/
class BinarySearchTree<T extends java.lang.Comparable<T>> {
/* the root of the tree is the only data field needed */
protected BinaryNode<T> root = null; // null when tree is empty
/* constructs an empty tree
*/
public BinarySearchTree() {
super();
}
/* constructs a tree with one element, as given
* @param value to be used for the one element in the tree
*/
public BinarySearchTree(T value) {
super();
root = new BinaryNode<T>(value);
}
/* constructs a tree with the given node as root
* @param newRoot to be used as the root of the new tree
*/
public BinarySearchTree(BinaryNode<T> newRoot) {
super();
root = newRoot;
}
/* find a value in the tree
* @param key identifies the node value desired
* @return the node value found, or null if not found
*/
public T get(T key) {
BinaryNode<T> node = root;
while (node != null) {
if (key.compareTo(node.getValue()) == 0) {
return node.getValue();
}
if (key.compareTo(node.getValue()) < 0) {
node = node.getLeft();
} else {
node = node.getRight();
}
}
return null;
}
/* add a value to the tree, replacing an existing value if necessary
* @param value to be inserted
*/
public void add(T value) {
root = add(value, root);
}
/* add a value to the tree, replacing an existing value if necessary
* @param value to be inserted
* @param node that is the root of the subtree in which to insert
* @return the subtree with the node inserted
*/
protected BinaryNode<T> add(T value, BinaryNode<T> node) {
if (node == null) {
return new BinaryNode<T>(value);
}
if (value.compareTo(node.getValue()) == 0) {
// replace the value in this node with a new value
node.setValue(value);
// alternative code creates new node, leaves old node unchanged:
//return new BinaryNode<T>(value, node.getLeft(), node.getRight());
} else {
if (value.compareTo(node.getValue()) < 0) { // add to left subtree
node.setLeft(add(value, node.getLeft()));
} else { // add to right subtree
node.setRight(add(value, node.getRight()));
}
}
return node;
}
/* remove a value from the tree, if it exists
* @param key such that value.compareTo(key) == 0 for the node to remove
*/
public void remove(T key) {
root = remove(key, root);
}
/* remove a value from the tree, if it exists
* @param key such that value.compareTo(key) == 0 for the node to remove
* @param node the root of the subtree from which to remove the value
* @return the new tree with the value removed
*/
protected BinaryNode<T> remove(T value, BinaryNode<T> node) {
if (node == null) { // key not in tree
return null;
}
if (value.compareTo(node.getValue()) == 0) { // remove this node
if (node.getLeft() == null) { // replace this node with right child
return node.getRight();
} else if (node.getRight() == null) { // replace with left child
return node.getLeft();
} else {
// replace the value in this node with value in the
// rightmost node of the left subtree
T replacement = getRightmost(node.getLeft());
// now remove the rightmost node in the left subtree,
// by calling ourselves recursively
BinaryNode<T> newNode = new
BinaryNode<T>(replacement,
remove(replacement, node.getLeft()),
node.getRight());
return newNode;
}
} else { // remove from left or right subtree
if (value.compareTo(node.getValue()) < 0) {
// remove from left subtree
node.setLeft(remove(value, node.getLeft()));
} else { // remove from right subtree
node.setRight(remove(value, node.getRight()));
}
}
return node;
}
//----------------------------------------------------------------------------//
/**
* finds a greatest record that is smaller than a given value in a binary
* search tree based a key value
*
* @param key identifies the value desired
* @return the previous node value if found, or null if not found
* @throws NoSuchElementException if the next node does not exist
*/
public T findPrevious(T key) {
if (key == null)
throw new NullPointerException("key");
return findPrevious(key, null, root);
}
/**
* finds a greatest record that is smaller than a given value in a binary
* search tree based a key value
*
* @param key identifies the value desired
* @param node is the root of the current subtree
* @param anchor keeps track of the parent node that might be the answer
* @return the previous node value if found, or null if not found
* @throws NoSuchElementException if the next node does not exist
*/
private T findPrevious(T key, BinaryNode<T> anchor, BinaryNode<T> node) {
// return null if there's no node matches with the key
if (node == null)
return null;
int comparison = key.compareTo(node.getValue());
// if the key node is found, return the right most node's value on its left
// subtree. If it don't have a left subtree, return the anchor's value. If
// the anchor didn't change, throw NoSuchElementException.
if (comparison == 0) {
if (node.getLeft() != null)
return rightMost(node.getLeft()).getValue();
if (anchor == null)
throw new NoSuchElementException();
return anchor.getValue();
}
// if the key is smaller than the current root's value, go left without
// change the anchor.
if (comparison < 0)
return findPrevious(key, anchor, node.getLeft());
// if the key is greater than the current root's value, update the anchor to
// the current root and go right.
return findPrevious(key, node, node.getRight());
}
/**
* finds a smallest record that is greater than a given value in a binary
* search tree based a key value
*
* @param key identifies the value desired
* @return the next node value if found, or null if not found
* @throws NoSuchElementException if the next node does not exist
*/
public T findNext(T key) {
if (key == null)
throw new NullPointerException("key");
return findNext(key, null, root);
}
/**
* finds a smallest record that is greater than a given value in a binary
* search tree based a key value
*
* @param key identifies the value desired
* @param node is the root of the current subtree
* @param anchor keeps track of the parent node that might be the answer
* @return the next node value if found, or null if not found
* @throws NoSuchElementException if the next node does not exist
*/
private T findNext(T key, BinaryNode<T> anchor, BinaryNode<T> node) {
// return null if there's no node matches with the key
if (node == null)
return null;
int comparison = key.compareTo(node.getValue());
// if the key node is found, return the left most node's value on its right
// subtree. If it don't have a right subtree, return the anchor's value. If
// the anchor doesn't updated, throw NoSuchElementException.
if (comparison == 0) {
if (node.getRight() != null)
return leftMost(node.getRight()).getValue();
if (anchor == null)
throw new NoSuchElementException();
return anchor.getValue();
}
// if the key is greater than the current root's value, go right without
// updating the anchor.
if (comparison > 0)
return findNext(key, anchor, node.getRight());
// if the key is smaller than the current root's value, update the anchor to
// the current root and go left.
return findNext(key, node, node.getLeft());
}
/**
* finds a right most node in the binary search tree from a given root
*
* @param node identifies the root node
* @return the node if found, or null if not found
*/
private BinaryNode<T> rightMost(BinaryNode<T> node) {
if (node == null)
return null;
if (node.getRight() == null)
return node;
return rightMost(node.getRight());
}
/**
* finds a left most node in the binary search tree from a given root
*
* @param node identifies the root node
* @return the node if found, or null if not found
*/
private BinaryNode<T> leftMost(BinaryNode<T> node) {
if (node == null)
return null;
if (node.getLeft() == null)
return node;
return leftMost(node.getLeft());
}
//----------------------------------------------------------------------------//
protected T getRightmost(BinaryNode<T> node) {
assert(node != null);
BinaryNode<T> result = node.getRight();
if (node.getRight() == null) {
return node.getValue();
} else {
return getRightmost(node.getRight());
}
}
/* iterator, traverses the tree in order */
public Iterator<T> iterator() {
return new TreeIterator<T>(root);
}
/* traverses the tree in pre-order */
public Iterator<T> preIterator() {
return new TreeIterator<T>(root, true);
}
/* traverses the tree in post-order */
public Iterator<T> postIterator() {
return new TreeIterator<T>(root, false);
}
/* toString
* @returns the string representation of the tree.
*/
public String toString() {
return toString(root);
}
protected String toString(BinaryNode<T> node) {
if (node == null) {
return "";
}
return node.toString() + '\n' + toString(node.getLeft()) +
toString(node.getRight());
}
/* unit test
* @param arguments, ignored
*/
public static void main(String[] arguments) {
BinarySearchTree<Integer> tree = new BinarySearchTree<Integer>();
tree.add(5);
tree.add(7);
tree.add(9);
tree.add(3);
tree.add(1);
tree.add(2);
tree.add(4);
tree.add(6);
tree.add(8);
tree.add(10);
System.out.println(tree);
Iterator<Integer> it = tree.preIterator();
System.out.print("pre-order: ");
while (it.hasNext()) {
System.out.print(it.next() + ", ");
}
System.out.println("");
it = tree.iterator();
System.out.print("in-order: ");
while (it.hasNext()) {
System.out.print(it.next() + ", ");
}
System.out.println("");
it = tree.postIterator();
System.out.print("post-order: ");
while (it.hasNext()) {
System.out.print(it.next() + ", ");
}
System.out.println("");
if (! tree.get(5).equals(5)) {
System.out.println("error: tree does not have 5");
}
if (tree.get(13) != null) {
System.out.println("error: tree has 13, should not");
}
if (! tree.get(10).equals(10)) {
System.out.println("error: tree does not have 10");
}
tree.add(10);
System.out.println(tree);
tree.remove(10);
tree.remove(2);
tree.remove(5);
tree.remove(9);
tree.remove(10);
tree.remove(9);
System.out.println(tree);
if (tree.get(5) != null) {
System.out.println("error: tree has 5, should not");
}
if (tree.get(13) != null) {
System.out.println("error: tree has 13, should not");
}
if (! tree.get(3).equals(3)) {
System.out.println("error: tree does not have 3");
}
}
}
/* a class for binary tree nodes
* @author Biagioni, Edoardo
* @assignment lecture 16
* @date March 10, 2008
* @inspiration William Albritton's binary tree node class,
* http://www2.hawaii.edu/~walbritt/ics211/treeBinarySearch/BinaryNode.java
* @inspiration the Node class,
* http://www2.ics.hawaii.edu/~esb/2008spring.ics211/Node.java.html
*/
class BinaryNode<T> {
/* three data fields, the first to store the item itself,
* the other two for the left and right subtree,
* either or both of which may be null.
*/
protected T item;
protected BinaryNode<T> left;
protected BinaryNode<T> right;
/* no-argument constructor sets everything to null */
public BinaryNode() {
item = null;
left = null;
right = null;
}
/* one-argument constructor: value as given, subtrees are null
* @param value, the value for the node
*/
public BinaryNode(T value) {
item = value;
left = null;
right = null;
}
/* constructor:
* @param value, the value for the node
* @param left, the left subtree
* @param right, the right subtree
*/
public BinaryNode(T value, BinaryNode<T> leftSubtree,
BinaryNode<T> rightSubtree) {
item = value;
left = leftSubtree;
right = rightSubtree;
}
/* accessor methods */
public T getValue() {
return item;
}
public BinaryNode<T> getLeft() {
return left;
}
public BinaryNode<T> getRight() {
return right;
}
/* mutator methods */
public void setValue(T value) {
item = value;
}
public void setLeft(BinaryNode<T> newLeft) {
left = newLeft;
}
public void setRight(BinaryNode<T> newRight) {
right = newRight;
}
/* toString
* @returns the string representation of the item.
*/
public String toString() {
return item + "";
}
/* unit test
* @param arguments, ignored
*/
public static void main(String[] arguments) {
BinaryNode<Integer> x = new BinaryNode<Integer>(); // no-arguments constructor
BinaryNode<Integer> y = new BinaryNode<Integer>(3);
BinaryNode<Integer> z = new BinaryNode<Integer>(9, x, y);
printXyz(x, y, z);
z.setValue(65);
x.setValue(new Integer(16));
printXyz(x, y, z);
}
private static void printXyz(BinaryNode<Integer> x, BinaryNode<Integer> y,
BinaryNode<Integer> z) {
System.out.println("x is the node " + x +
", with left " + x.getLeft() +
" and right " + x.getRight());
System.out.println("y is the node " + y +
", with left " + y.getLeft() +
" and right " + y.getRight());
System.out.println("z is the node " + z +
", with left " + z.getLeft() +
" and right " + z.getRight());
}
}
/* an iterator class to iterate over binary trees
* @author Biagioni, Edoardo
* @assignment lecture 17
* @date March 12, 2008
*/
class TreeIterator<T> implements Iterator<T> {
/* the class variables keep track of how much the iterator
* has done so far, and what remains to be done.
* root is null when the iterator has not been initialized,
* or the entire tree has been visited.
* the first stack keeps track of the last node to return
* and all its ancestors
* the second stack keeps track of whether the node visited
* is to the left (false) or right (true) of its parent
*/
protected BinaryNode<T> root = null;
protected Stack<BinaryNode<T>> visiting = new Stack<BinaryNode<T>>();
protected Stack<Boolean> visitingRightChild = new Stack<Boolean>();
/* only one of these booleans can be true */
boolean preorder = false;
boolean inorder = true;
boolean postorder = false;
/* constructor for in-order traversal
* @param root of the tree to traverse
*/
public TreeIterator(BinaryNode<T> root) {
this.root = root;
visiting = new Stack<BinaryNode<T>>();
visitingRightChild = new Stack<Boolean>();
preorder = false;
inorder = true;
postorder = false;
}
/* constructor for pre-order or post-order traversal
* @param root of the tree to traverse
* @param inPreorder true if pre-order, false if post-order
*/
public TreeIterator(BinaryNode<T> root, boolean inPreorder) {
this.root = root;
visiting = new Stack<BinaryNode<T>>();
visitingRightChild = new Stack<Boolean>();
preorder = inPreorder;
inorder = false;
postorder = ! preorder;
}
public boolean hasNext() {
return (root != null);
}
public T next() {
if (! hasNext()) {
throw new java.util.NoSuchElementException("no more elements");
}
if (preorder) {
return preorderNext();
} else if (inorder) {
return inorderNext();
} else if (postorder) {
return postorderNext();
} else {
assert(false);
return null;
}
}
// return the node at the top of the stack, push the next node if any
private T preorderNext() {
if (visiting.empty()) { // at beginning of iterator
visiting.push(root);
}
BinaryNode<T> node = visiting.pop();
T result = node.getValue();
// need to visit the left subtree first, then the right
// since a stack is a LIFO, push the right subtree first, then
// the left. Only push non-null trees
if (node.getRight() != null) {
visiting.push(node.getRight());
}
if (node.getLeft() != null) {
visiting.push(node.getLeft());
}
// may not have pushed anything. If so, we are at the end
if (visiting.empty()) { // no more nodes to visit
root = null;
}
return node.getValue();
}
/* find the leftmost node from this root, pushing all the
* intermediate nodes onto the visiting stack
* @param node the root of the subtree for which we
* are trying to reach the leftmost node
* @changes visiting takes all nodes between node and the leftmost
*/
private void pushLeftmostNode(BinaryNode<T> node) {
// find the leftmost node
if (node != null) {
visiting.push(node); // push this node
pushLeftmostNode(node.getLeft()); // recurse on next left node
}
}
/* return the leftmost node that has not yet been visited
* that node is normally on top of the stack
* inorder traversal doesn't use the visitingRightChild stack
*/
private T inorderNext() {
if (visiting.empty()) { // at beginning of iterator
// find the leftmost node, pushing all the intermediate nodes
// onto the visiting stack
pushLeftmostNode(root);
} // now the leftmost unvisited node is on top of the visiting stack
BinaryNode<T> node = visiting.pop();
T result = node.getValue(); // this is the value to return
// if the node has a right child, its leftmost node is next
if (node.getRight() != null) {
BinaryNode<T> right = node.getRight();
// find the leftmost node of the right child
pushLeftmostNode (right);
// note "node" has been replaced on the stack by its right child
} // else: no right subtree, go back up the stack
// next node on stack will be next returned
if (visiting.empty()) { // no next node left
root = null;
}
return result;
}
/* find the leftmost node from this root, pushing all the
* intermediate nodes onto the visiting stack
* and also stating that each is a left child of its parent
* @param node the root of the subtree for which we
* are trying to reach the leftmost node
* @changes visiting takes all nodes between node and the leftmost
*/
private void pushLeftmostNodeRecord(BinaryNode<T> node) {
// find the leftmost node
if (node != null) {
visiting.push(node); // push this node
visitingRightChild.push(false); // record that it is on the left
pushLeftmostNodeRecord(node.getLeft()); // continue looping
}
}
//
private T postorderNext() {
if (visiting.empty()) { // at beginning of iterator
// find the leftmost node, pushing all the intermediate nodes
// onto the visiting stack
pushLeftmostNodeRecord(root);
} // the node on top of the visiting stack is the next one to be
// visited, unless it has a right subtree
if ((visiting.peek().getRight() == null) || // no right subtree, or
(visitingRightChild.peek())) { // right subtree already visited
// already visited right child, time to visit the node on top
T result = visiting.pop().getValue();
visitingRightChild.pop();
if (visiting.empty()) {
root = null;
}
return result;
} else { // now visit this node's right subtree
// pop false and push true for visiting right child
if (visitingRightChild.pop()) {
assert(false);
}
visitingRightChild.push(true);
// now push everything down to the leftmost node
// in the right subtree
BinaryNode<T> right = visiting.peek().getRight();
assert(right != null);
pushLeftmostNodeRecord(right);
// use recursive call to visit that node
return postorderNext();
}
}
/* not implemented */
public void remove() {
throw new java.lang.UnsupportedOperationException("remove");
}
/* give the entire state of the iterator: the tree and the two stacks */
public String toString() {
if (preorder) {
return "pre: " + toString(root) + "\n" + visiting + "\n";
}
if (inorder) {
return "in: " + toString(root) + "\n" + visiting + "\n";
}
if (postorder) {
return "post: " + toString(root) + "\n" + visiting + "\n" +
visitingRightChild;
}
return "none of pre-order, in-order, or post-order are true";
}
private String toString(BinaryNode<T> node) {
if (node == null) {
return "";
} else {
return node.toString() + "(" + toString(node.getLeft()) + ", " +
toString(node.getRight()) + ")";
}
}
/* unit test
* @param arguments, ignored
*/
public static void main(String[] arguments) {
BinaryNode<String> x = new BinaryNode<String>("x");
BinaryNode<String> z = new BinaryNode<String>("z");
BinaryNode<String> y = new BinaryNode<String>("y", x, z);
testIterator(new TreeIterator<String>(y));
testIterator(new TreeIterator<String>(y, true));
testIterator(new TreeIterator<String>(y, false));
BinaryNode<String> a = new BinaryNode<String>("a");
BinaryNode<String> c = new BinaryNode<String>("c");
BinaryNode<String> b = new BinaryNode<String>("b", a, null);
BinaryNode<String> m = new BinaryNode<String>("m", b, y);
testIterator(new TreeIterator<String>(m));
testIterator(new TreeIterator<String>(m, true));
testIterator(new TreeIterator<String>(m, false));
}
public static void testIterator(Iterator<String> it) {
System.out.println("it = " + it);
while (it.hasNext()) {
String result = it.next();
System.out.println("it.next gives " + result + "\n it = " + it);
}
}
}
/* a class for taxpayers in a database
* @author Biagioni, Edoardo
* @assignment lecture 17
* @date March 12, 2008
* @inspiration William Albritton's Person class,
* http://www2.hawaii.edu/~walbritt/ics211/treeBinarySearch/Person.java
*/
class Taxpayer implements java.lang.Comparable<Taxpayer> {
String name; // the taxpayer's full name
int SSN; // the taxpayer's social security number
double tax; // amount of tax owed by or to the taxpayer
/* constructor */
public Taxpayer(String name, int SSN, double tax) {
this.name = name;
this.SSN = SSN;
this.tax = tax;
}
/* a constructor to build a taxpayer record that is a key, that is,
* only the SSN is of interest
*/
public Taxpayer(int SSN) {
this.SSN = SSN;
}
/* accessor methods */
public String getName() {
return name;
}
public int getSSN() {
return SSN;
}
public double getTax() {
return tax;
}
/* mutator methods */
public void getName(String newName) {
name = newName;
}
public void setSSN(int newSSN) {
SSN = newSSN;
}
public void setTax(double newTax) {
tax = newTax;
}
public int compareTo(Taxpayer recordOrKey) {
/* only use SSN field, which exists in a key as well as in a complete
* record */
return SSN - recordOrKey.SSN;
}
public String toString() {
return "name: " + name + ", SSN: " + SSN + ", tax due: " + tax;
}
}