CS 136 - Lecture 28

  1. Binary Search Trees (cont'd)
    1. Binary Search Tree Implementation

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();
          child = subRoot.left();
        // if no child there: not in tree, return this node,
        // else keep searching
        if (child == null) 
          return subRoot;
          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;

    public void add(Object val)
    // 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))
          else {
            if (insertLocation.left() != null)
            // if value is in tree, we insert just before

    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();
          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);
          Object result = root.value();
          root = newroot;
          return result;
        } else {
          BinaryTreeNode location = locate(root,cval);

          if (cval.equals(location.value())) {
            BinaryTreeNode parent = location.parent();
            if (parent.right() == 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
        // 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)
          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
        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.