// An implementation of nodes for use in binary trees. // (c) 1998, 2001 duane a. bailey import structure.*; import java.lang.Math; import java.util.Iterator; /** * This class implements a single node of a binary tree. It is a recursive * structure. Relationships between nodes are doubly linked, with parent and * child references. Many characteristics of trees may be detected with static * methods. * * @version $Id: BinaryTree.java,v 4.0 2000/12/27 20:57:33 bailey Exp bailey $ * @author, 2001 duane a. bailey * @see structure.BinaryTree * @see structure.BinarySearchTree */ public class BinaryTree implements BinaryTreeInterface { /** * The value associated with this node */ protected Object val; // value associated with node /** * The parent of this node */ protected BinaryTreeInterface parent = EMPTY; // parent of node /** * The left child of this node, or EMPTY */ protected BinaryTreeInterface left = EMPTY, right = EMPTY; // children of node /** * Constructs a tree node with no children. Value of the node is provided by * the user * * @post Returns a tree referencing value with two EMPTY subtrees * * @param value * A (possibly null) value to be referenced by node */ public BinaryTree(Object value) { val = value; } /** * Constructs a tree node with no children. Value of the node and subtrees * are provided by the user * * @post Returns a tree referencing value and subtree * * @param value * A (possibly null) value to be referenced by node * @param left * The subtree to be left subtree of node * @param right * The subtree to be right subtree of node */ public BinaryTree(Object value, BinaryTreeInterface left, BinaryTreeInterface right) { val = value; setLeft(left); setRight(right); } /** * Get left subtree of current node * * @post Returns reference to left subtree * * @return The left subtree of this node */ public BinaryTreeInterface left() { return left; } /** * Get right subtree of current node * * @post Returns reference to right subtree * * @return The right subtree of this node */ public BinaryTreeInterface right() { return right; } /** * Get reference to parent of this node * * @post Returns reference to parent node * * @return Reference to parent of this node */ public BinaryTreeInterface parent() { return parent; } /** * Update the left subtree of this node. Parent of the left subtree is * updated consistently. Existing subtree is detached * * @post Sets left subtree to newLeft re-parents newLeft * * @param newLeft * The root of the new left subtree */ public void setLeft(BinaryTreeInterface newLeft) { left.setParent(EMPTY); left = newLeft; left.setParent(this); } /** * Update the right subtree of this node. Parent of the right subtree is * updated consistently. Existing subtree is detached * * @post Sets left subtree to newRight re-parents newRight * * @param newRight * A reference to the new right subtree of this node */ public void setRight(BinaryTreeInterface newRight) { right.setParent(EMPTY); right = newRight; right.setParent(this); } /** * Update the parent of this node * * @post Re-parents this node to parent reference * * @param newParent * A reference to the new parent of this node */ public void setParent(BinaryTreeInterface newParent) { parent = newParent; } /** * Returns the number of descendants of node * * @post Returns the size of the subtree * * @return Size of subtree */ public int size() { return left().size() + right().size() + 1; } /** * Returns reference to root of tree containing n * * @post Returns the root of the tree node n * * @return Root of tree */ public BinaryTreeInterface root() { if (parent() == EMPTY) return this; else return parent().root(); } /** * Returns height of node in tree. Height is maximum path length to * descendant * * @post Returns the height of a node in its tree * * @return The height of the node in the tree */ public int height() { return 1 + Math.max(left.height(), right.height()); } /** * Compute the depth of a node. The depth is the path length from node to * root * * @post Returns the depth of a node in the tree * * @return The path length to root of tree */ public int depth() { if (parent() == EMPTY) return 0; return 1 + parent.depth(); } /** * Returns true if tree is full. A tree is full if adding a node to tree * would necessarily increase its height * * @post Returns true iff the tree rooted at node is full * * @return True iff tree is full */ public boolean isFull() { if (left().height() != right().height()) return false; return left().isFull() && right().isFull(); } /** * Returns true if tree is empty. @post Returns true iff the tree rooted at * node is empty * * @return True iff tree is empty */ public boolean isEmpty() { return false; } /** * Return whether tree is complete. A complete tree has minimal height and * any holes in tree would appear in last level to right. * * @post Returns true iff the tree rooted at node is complete * * @return True iff the subtree is complete */ public boolean isComplete() { int leftHeight, rightHeight; boolean leftIsFull, rightIsFull; boolean leftIsComplete, rightIsComplete; leftHeight = left().height(); rightHeight = right().height(); leftIsFull = left().isFull(); rightIsFull = right().isFull(); leftIsComplete = left().isComplete(); rightIsComplete = right().isComplete(); // case 1: left is full, right is complete, heights same if (leftIsFull && rightIsComplete && (leftHeight == rightHeight)) return true; // case 2: left is complete, right is full, heights differ if (leftIsComplete && rightIsFull && (leftHeight == (rightHeight + 1))) return true; return false; } /** * Return true iff the tree is height balanced. A tree is height balanced * iff at every node the difference in heights of subtrees is no greater * than one * * @post Returns true iff the tree rooted at node is balanced * * @return True if tree is height balanced */ public boolean isBalanced() { return (Math.abs(left().height() - right().height()) <= 1) && left().isBalanced() && right().isBalanced(); } /** * Determine if this node is a left child * * @post Returns true if this is a left child of parent * * @return True iff this node is a left child of parent */ public boolean isLeftChild() { return this == parent().left(); } /** * Determine if this node is a right child * * @post Returns true if this is a right child of parent * * @return True iff this node is a right child of parent */ public boolean isRightChild() { return this == parent().right(); } /** * Returns value associated with this node * * @post Returns value associated with this node * * @return The node's value */ public Object value() { return val; } /** * Set's value associated with this node * * @post Sets the value associated with this node * * @param value * The new value of this node */ public void setValue(Object value) { val = value; } /** * Generate an in-order iterator of subtree * * @post Returns an in-order iterator of the elements * * @return In-order iterator on subtree rooted at this */ public Iterator iterator() { return inorderIterator(); } /** * Return an iterator to traverse nodes of subtree in-order * * @post The elements of the binary tree rooted at node are traversed in * preorder * * @return AbstractIterator to traverse subtree */ public AbstractIterator preorderIterator() { return new BTPreorderIterator(this); } /** * Return an iterator to traverse the elements of subtree in-order * * @post The elements of the binary tree rooted at node node are traversed * in inorder * * @return An in-order iterator over descendants of node */ public AbstractIterator inorderIterator() { return new BTInorderIterator(this); } /** * Return an iterator to traverse the elements of subtree in post-order * * @pre None @post The elements of the binary tree rooted at node node are * traversed in postorder * * @return An iterator that traverses descendants of node in postorder */ public AbstractIterator postorderIterator() { return new BTPostorderIterator(this); } /** * Method to return a level-order iterator of subtree * * @pre None @post The elements of the binary tree rooted at node node are * traversed in levelorder * * @return An iterator to traverse subtree in level-order */ public AbstractIterator levelorderIterator() { return new BTLevelorderIterator(this); } /** * Method to perform a right rotation of tree about this node Node must have * a left child. Relation between left child and node are reversed * * @pre This node has a left subtree @post Rotates local portion of tree so * left child is root */ protected void rotateRight() { BinaryTreeInterface parent = parent(); BinaryTreeInterface newRoot = left(); boolean wasChild = parent != EMPTY; boolean wasLeftChild = isLeftChild(); // hook in new root (sets newRoot's parent, as well) setLeft(newRoot.right()); // puts pivot below it (sets this's parent, as well) newRoot.setRight(this); if (wasChild) { if (wasLeftChild) parent.setLeft(newRoot); else parent.setRight(newRoot); } } /** * Method to perform a left rotation of tree about this node Node must have * a right child. Relation between right child and node are reversed * * @pre This node has a right subtree @post Rotates local portion of tree so * right child is root */ protected void rotateLeft() { // all of this information must be grabbed before // any of the references are set. Draw a diagram for help BinaryTreeInterface parent = parent(); BinaryTreeInterface newRoot = right(); // is the this node a child; if so, a left child? boolean wasChild = parent != EMPTY; boolean wasRightChild = isRightChild(); // hook in new root (sets newRoot's parent, as well) setRight(newRoot.left()); // put pivot below it (sets this's parent, as well) newRoot.setLeft(this); if (wasChild) { if (wasRightChild) parent.setRight(newRoot); else parent.setLeft(newRoot); } } /** * @post return sum of hashcodes of the contained values */ public int hashCode() { if (isEmpty()) return 0; int result = left().hashCode() + right().hashCode(); if (value() != null) result += value().hashCode(); return result; } /** * Returns a string representing the tree rooted at this node. * WARNING this can be a very long string. * * @return A string representing the tree rooted at this node. */ public String treeString() { String s = ""; for (int i = 0; i < this.depth(); i++) { s += "\t|"; } s += ("<" + val + " : " + getHand() + ">\n"); if (left != EMPTY) s += left.treeString(); if (right != EMPTY) s += right.treeString(); return s; } /** * Support method for {@link #toString}. Returns R if this is node is a * right child, L if this node is a left child and Root if this node is the * root. * * @return R if this is node is a right child, L if this node is a left * child and Root if this node is the root. */ private String getHand() { if (isRightChild()) return "R"; if (isLeftChild()) return "L"; return "Root"; } /** * Returns a representation the subtree rooted at this node * * @post Returns string representation * * @return String representing this subtree */ public String toString() { StringBuffer s = new StringBuffer(); s.append("'); return s.toString(); } }