// 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();
}
}