/* * File: ZHBinaryTreeStructure.java */ package zhstructures; import java.util.Iterator; /** * Abstract class that provides a node structure for one-way linked implementations of * binary trees.
* * Implementing classes will typically use this class in one of two ways. They may extend * this class, passing their own class name (with the generic ElementType parameter) as the * StructureType parameter. In this case, implementing classes should only call constructors * of this class from within their own constructors. This method is most often used for a * situation in which the implementing class needs a single reference to a fixed starting * node. A typical declaration of this type might be:
* * public class Foo\ * extends ZHBinaryTreeStructure\\> ...
* * The second way to use this class occurs when the implementing class needs one or more * variable references to nodes. In this case, the implementing class declares a protected * inner class that extends this class and one or more instance variables of the inner * class type. Such an inner class need only implement constructors that match the * constructors of this class.
* * @param ElementType the type of data elements contained in this structure * @param StructureType a class extending this class that is to be used in a particular * collection * * @author J. Andrew Holey * @version November 4, 2008 */ public abstract class ZHBinaryTreeStructure > implements ZHCollection { /** * The data element associated with this node, if it is not empty */ protected ElementType element; /** * The node representing the left subtree of this node, * if it is not empty */ protected StructureType leftChild; /** * The node representing the right subtree of this node, * if it is not empty */ protected StructureType rightChild; /** * The state of this node: either ZHNodeState.EMPTY or ZHNodeState.NOT_EMPTY */ protected ZHComponentState state; /** * Creates a new empty node. * * Instance variables--element, leftChild and rightChild--are not used in * empty nodes and so are left uninitialized. */ public ZHBinaryTreeStructure() { this.state = ZHComponentState.EMPTY; } /** * Creates a new non-empty node with the specified element, left child and * right child. * * @param element the data element associated with this node * @param leftChild the node representing the left subtree in this structure, * should generally be an actual node rather than null * @param rightChild the node representing the right subtree in this structure, * should generally be an actual node rather than null */ public ZHBinaryTreeStructure(ElementType element, StructureType leftChild, StructureType rightChild) { this.element = element; this.leftChild = leftChild; this.rightChild = rightChild; this.state = ZHComponentState.NOT_EMPTY; } /* (non-Javadoc) * @see zhstructures.ZHCollection#isEmpty() */ @Override public boolean isEmpty() { switch (this.state) { case EMPTY: return true; case NOT_EMPTY: return false; default: throw new IllegalStateException(); } } /* (non-Javadoc) * @see zhstructures.ZHCollection#contains(java.lang.Object) */ @Override public boolean contains(ElementType element) { StructureType target = this.find(element); switch (target.state) { case EMPTY: return false; case NOT_EMPTY: return true; default: throw new IllegalStateException(); } } /** * Returns an element in this tree structure that matches the specified element * or null if no such element exists. * * @param element the element to search for * @return an element in this tree structure that matches the specified element * or null if no such element exists */ public ElementType get(ElementType element) { StructureType target = this.find(element); switch (target.state) { case EMPTY: return null; case NOT_EMPTY: return target.element; default: throw new IllegalStateException(); } } /* (non-Javadoc) * @see zhstructures.ZHCollection#iterator() */ @Override public abstract Iterator iterator(); /** * Returns an inorder iterator for this tree structure. This iterator does not * back the tree; that is, the iterator is not affected to changes made in the * tree subsequent to the creation of the iterator. * * @return an inorder iterator for this tree structure */ public Iterator inorderIterator() { ZHQueue queue = new ZHLinkedQueue(); this.traverseInorder(queue); return new ZHIterator(queue.iterator()); } /** * Returns a postorder iterator for this tree structure. This iterator does not * back the tree; that is, the iterator is not affected to changes made in the * tree subsequent to the creation of the iterator. * * @return a postorder iterator for this tree structure */ public Iterator postorderIterator() { ZHQueue queue = new ZHLinkedQueue(); this.traversePostorder(queue); return new ZHIterator(queue.iterator()); } /** * Returns a preorder iterator for this tree structure. This iterator does not * back the tree; that is, the iterator is not affected to changes made in the * tree subsequent to the creation of the iterator. * * @return a preorder iterator for this tree structure */ public Iterator preorderIterator() { ZHQueue queue = new ZHLinkedQueue(); this.traversePreorder(queue); return new ZHIterator(queue.iterator()); } /** * Returns a subtree with the specified element in its root if such a subtree exits; * otherwise, returns the rightmost empty subtree. * * @param element the element to search for * @return a subtree with the specified element in its root if such a subtree exits; * otherwise, returns the rightmost empty subtree. * @throws ClassCastException if this ZHBinaryTreeStructure is not an instance of * StructureType. */ @SuppressWarnings("unchecked") protected StructureType find(ElementType element) { StructureType result; if (this.isEmpty() || this.element.equals(element)) { result = (StructureType) this; } else { result = this.leftChild.find(element); if (result.isEmpty()) result = this.rightChild.find(element); } return result; } /** * Returns the leftmost non-empty subtree of this tree (possibly this) * or this if this tree structure is empty. * * @return the leftmost non-empty subtree of this tree (possibly this) * or this if this tree structure is empty */ @SuppressWarnings("unchecked") protected StructureType findLeftmost() { if (this.isEmpty()) return (StructureType) this; return this.findLeftmostWhenNotEmpty(); } @SuppressWarnings("unchecked") private StructureType findLeftmostWhenNotEmpty() { if (this.leftChild.isEmpty()) return (StructureType) this; return this.leftChild.findLeftmostWhenNotEmpty(); } private void traverseInorder(ZHQueue queue) { switch (this.state) { case EMPTY: // nothing to add break; case NOT_EMPTY: this.leftChild.traverseInorder(queue); queue.enqueue(this.element); this.rightChild.traverseInorder(queue); break; default: // this code should never be reached; // throwing this exception indicates a programming error in this class // or in a subclass throw new IllegalStateException(); } } private void traversePostorder(ZHQueue queue) { switch (state) { case EMPTY: // nothing to add break; case NOT_EMPTY: this.leftChild.traversePostorder(queue); this.rightChild.traversePostorder(queue); queue.enqueue(this.element); break; default: // this code should never be reached; // throwing this exception indicates a programming error in this class // or in a subclass throw new IllegalStateException(); } } private void traversePreorder(ZHQueue queue) { switch (state) { case EMPTY: // nothing to add break; case NOT_EMPTY: queue.enqueue(this.element); this.leftChild.traversePreorder(queue); this.rightChild.traversePreorder(queue); break; default: // this code should never be reached; // throwing this exception indicates a programming error in this class // or in a subclass throw new IllegalStateException(); } } }