CS 136 - Lecture 28

Binary Search Tree Implementation

Because it stores items in order, it is an implementation of OrderedStructure. We'll skip implementation of obvious methods, to focus on harder methods: add, get, and remove. We'll add protected methods locate, predecessor, and removeTop to make add, get, and remove easier.

```public class BinarySearchTree implements OrderedStructure
{
protected BinaryTreeNode root;
protected int count;

public BinarySearchTree()
// post: constructs an empty binary search tree.
{
root = null;
count = 0;
}

public boolean isEmpty()
// post: returns true iff binary search tree is empty.

public void clear()
// post: removes all elements from binary search tree

public int size()
// post: returns number of elements in binary search tree

protected BinaryTreeNode locate(BinaryTreeNode subRoot,
Comparable value)
// pre: subRootand value are non-null
// post: returned: 1 - existing tree node with the desired value, or
//                 2 - node to which value should be added.
{
Comparable subRootValue = (Comparable)subRoot.value();
BinaryTreeNode child;

// found at root: done
if (subRootValue.equals(value)) return subRoot;
// look left, if less, right if more
if (subRootValue.lessThan(value))
child = subRoot.right();
else
child = subRoot.left();
// if no child there: not in tree, return this node,
// else keep searching
if (child == null)
return subRoot;
else
return locate(child, value);
}

protected BinaryTreeNode predecessor(BinaryTreeNode root)
// pre: tree is not empty, root node has left child.
// post: returns pointer to predecessor of root
{
Assert.pre(root != null, "No predecessor to middle value.");
Assert.pre(root.left() != null, "Root has left child.");
BinaryTreeNode result = root.left();
while (result.right() != null)
result = result.right();
return result;
}

protected BinaryTreeNode successor(BinaryTreeNode root)
// pre: tree is not empty, root node has right child.
// post: returns pointer to successor of root
{
Assert.pre(root != null, "Tree is non-null.");
Assert.pre(root.left() != null,"Root has right child.");
BinaryTreeNode result = root.right();
while (result.left() != null)
result = result.left();
return result;
}

// post: adds a value to the binary search tree.
{
BinaryTreeNode newNode = new BinaryTreeNode(val);

// add value to binary search tree
// if there's no root, create value at root.
if (root == null)
root = newNode;
else {
Comparable value = (Comparable)val;
BinaryTreeNode insertLocation = locate(root,value);
Comparable nodeValue = (Comparable)insertLocation.value();
// Location returned is the successor or predecessor
// of the to-be-inserted value.
if (nodeValue.lessThan(value))
insertLocation.setRight(newNode);
else {
if (insertLocation.left() != null)
// if value is in tree, we insert just before
predecessor(insertLocation).setRight(newNode);
else
insertLocation.setLeft(newNode);
}
}
count++;
}

public boolean contains(Object val)
// post: returns true iff val is found within the tree
{
if (root == null) return false;

BinaryTreeNode possibleLocation = locate(root,(Comparable)val);
return val.equals(possibleLocation.value());
}

public Object get(Object val)
// post: returns object found in tree, or null
{
if (root == null) return null;

BinaryTreeNode possibleLocation = locate(root,(Comparable)val);
if (val.equals(possibleLocation.value()))
return possibleLocation.value();
else
return null;
}

public Object remove(Object val)
// post: removes one instance of val, if found
{
// remove value from a binary search tree
// no root, just quit
Comparable cval = (Comparable)val;

if (isEmpty()) return null;

if (val.equals(root.value())) // delete root value
{
BinaryTreeNode newroot = removeTop(root);
count--;
Object result = root.value();
root = newroot;
return result;
} else {
BinaryTreeNode location = locate(root,cval);

if (cval.equals(location.value())) {
count--;
BinaryTreeNode parent = location.parent();
if (parent.right() == location)
parent.setRight(removeTop(location));
else
parent.setLeft(removeTop(location));
return location.value();
}
}
return null;
}

protected BinaryTreeNode removeTop(BinaryTreeNode topNode)
// pre: tree is not empty.
// post: root of tree (topNode) is disconnected from tree
//       & new root is returned, new root has no parent.

{
// remove topmost BinaryTreeNode from binary search tree
BinaryTreeNode left  = topNode.left();
BinaryTreeNode right = topNode.right();
// disconnect top node
topNode.setLeft(null);
topNode.setRight(null);
// Case a, no left BinaryTreeNode
//   easy: right subtree is new tree
if (left == null)  return right;
// Case b, no right BinaryTreeNode
//   easy: left subtree is new tree
if (right == null) return left;
// Case c, left node has no right subtree
//   easy: make right subtree of left
BinaryTreeNode predecessor = left.right();
if (predecessor == null)
{
left.setRight(right);
return left;
}
// General case, slide down left tree
//   harder: predecessor of root becomes new root
//           parent always points to parent of n
BinaryTreeNode parent = left;
while (predecessor.right() != null)
{
parent = predecessor;
predecessor = predecessor.right();
}
// Assert: n is predecessor of root
parent.setRight(predecessor.left());
predecessor.setLeft(left);
predecessor.setRight(right);
return predecessor;
}

...
}
```
Complexity of add, get, contains, and remove all proportional to height of tree. If balanced, then O(log n), otherwise O(n) in worst case.