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; } 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)) 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.