The Comparable Interface
As we start developing code to implement Binary Search Trees, we're going to need a way of comparing different Objects. The Java Comparable interface provides this functionality in the form of the compareTo() method. So, instead of dealing with Objects, our trees will store Comparable Objects -- only those Objects that implement the Comparable interface. Although you have used the compareTo() method in lab, we never did formally introduce it in lecture -- so we'll do that now.The Comparable Interface defines only one method: int compareTo(Object o).
Let's consider a.compareTo(b). In this case, compareTo() will return 1 if a is greater than b, 0 if the two are equal, or -1 if a is less than b.
Remember, the compareTo() method must be defined in each Object that implements the Comparable interface. It is in this definition where the implementor of how the particular type of Object is compared.
The Big Picture
Much like our LinkedList and DoublyLinkedList classes, our BST will require two related classes: a BSTNode to represent the data and the left and right subtrees, and the BST, itself, which will contain the root of the tree and all of the methods, such as insert() and find(), that manipulate it. cThe root of the BST class serves a very similar purpose to the head of the LinkedList -- it gives us a place to start. And the left and right references within the BSTNode are analagous to the prev and next references within a doubly linked list node. They name other, related, nodes that are part of the tree structure. And, as before, the data member will be accessible, but immutable. The other references within the BSTNode will be mutable.
Inserting Into A Binary Search Tree
We already went through the process of building a tree when we created the "HELLO WORLD" tree, so now let's take a look at some code to perform the insertion. Since trees are naturally recursive, we will use recursion. The root parameter in this code is the current subtree, not necessarily the root of the original tree. We search for the position to insert the new node, by cutting the original tree in half with each examination, and determining which half to search. We then call the insert method recursively on the correct half of the tree, by passing it either the left child or the right child of the root from the previous recursive activation.
// "root" here is the root of the current subtree void BSTinsert(BinaryTreeNode root, Comparable data) { // if the tree is initially empty, the data we // add becomes the root of the tree if (null == this.root) { this.root = new BinaryTreeNode(data); return; } // if the current data matches the data we want to // insert, it is already in the tree so we ignore it if (root.data().compareTo(data) == 0) { return; } // if the current data is greater than the one we // want to add, we need to go to the left if (root.data().compareTo(data) > 0) { // if the left is null, we can add data there if (root.left() == null) { root.setLeft(new BinaryTreeNode(data)); return; } // if not, we need to recursively insert into the // subtree on the left else { BSTinsert(root.left(), data); return; } } // if the current data is less than the one we want // to add, we need to go to the right else { // if the right is null, we can add data there if (root.right() == null) { root.setRight(new BinaryTreeNode(data)); return; } // if not, we need to recursively insert into the // subtree on the right else { BSTinsert(root.right(), data); return; } } }
Searching in a Binary Search Tree
As with insert(), this is implemented recursively. It returns the data, if found, or throws an exception, otherwise.
Comparable BSTfind(Node root, Comparable findMe) throws NotFoundException { // if the current subtree is null, the findMe // can't possible be in it if (null == root) { thrown new NotFoundException("Item not found in BST.") } // if the current data matches findMe, we have // found it so we can return it if (root.data().compareTo(findMe) == 0) { return root.data(); } // if the current data is greater than findMe, then // if findMe is in the tree it must be to the left, // so we will recursively search the left subtree if (root.data().compareTo(findMe) > 0) { return BSTfind(root.left()); } // if the current data is less than findMe, then // if findMe is in the tree it must be to the right, // so we will recursively search the right subtree else { return BSTfind(root.right()); } }