Main Page | Compound List | File List | Compound Members

BinaryTree Class Reference

List of all members.

Detailed Description

This class supports insertion and deletion of elements in a simple binary tree (e.g., the tree is not a balanced tree like an AVL tree or a red-black tree).

Relative to a particular node, nodes on the left are less than the node and nodes on the right are greater.

The Java class library includes the java.util.TreeMap class which is a balanced Red-Black tree which is recommended over this code. As with this class, the TreeMap class supports both insertion and deletion.

This class is not intended as a replacement for the TreeMap class. It was written to some degree as an excercise and demonstration. It uses a classic binary tree algorthm for both insert and delete. In contrast to the TreeMap algorithm, which uses left, right and parent references, this class uses only left and right references. As a result, this algorithm mirrors similar binary tree algorithms that might be implemented in C, C++, Pascal, or Modula-X.

This code is an interesting example of the problems that can be encountered in Java, where only pass-by-value is supported. The classic tree delete algorithm, which depends on pass by reference becomes much more awkward. A reference object is used in this code, which supports indirection. Since all references are made through the reference object, the code is more difficult to write and to understand that it would be for a language like C++ which supports reference arguments.

This object is not synchronized, so it is not safe for multi-threaded use.


Public Member Functions

 BinaryTree (Comparator compareObj)
 The constructor is initialized with an instance of the Comparator interface, which supports the compare() method which is used to compare objects in the tree with a search key.

String toString ()
 Return a String which contains the tree represented in "landscape" form, running down the page.

Object[] toArray ()
 Return an ordered array of tree objects, where Object values (as determined by the Comparator object used to initialize the BinaryTree constructor) increase with the array indices (e.g., the smallest value is at index 0, the largest value is at index n.

Object insert (Object newObj)
 Insert an object in the tree if it is not already present.

Object search (Object key)
 Search for an object in the tree that compares equal to key.

Object delete (Object key)
 Search the tree for an object which compares equal to key.

int size ()
 Return the number of data items (Objects) in the tree.


Private Member Functions

Node unlink (NodeReference root)
 When a value is removed from an ordered binary tree and the value has two children, it will be replaced by the next value in the right sub-branch which is greater.

Object delete (NodeReference root, Object key)
 This function searches a binary tree for "key" and deletes the item from the tree if it found.

Object searchAndInsert (NodeReference root, Object key, boolean insert)
 Recursive tree search and insert.

String spaces (int count)
 Return a string consisting of count spaces.

void toString (NodeReference root, PrintStream ps, int indent)
 Recursively build up a "landscape" display for the tree (e.g., a tree running down the page).

void toArray (Node root, Vector vec)
 Recursively traverse the tree (using inorder tranversal) and insert the Objects from the tree into a Vector.


Private Attributes

NodeReference root
 root of the binary tree

int mNodeCount
 Number of nodes in the binary tree.

Comparator mCompare
 Object used to compare Objects in the tree.


Constructor & Destructor Documentation

BinaryTree.BinaryTree Comparator  compareObj  ) 
 

The constructor is initialized with an instance of the Comparator interface, which supports the compare() method which is used to compare objects in the tree with a search key.

The equals() method of the Comparator interface is not used and should return false.

00170     {
00171         root = new NodeReference();
00172         mNodeCount = 0;
00173         mCompare = compareObj;
00174     } // BinaryTree


Member Function Documentation

Object BinaryTree.delete Object  key  ) 
 

Search the tree for an object which compares equal to key.

If the object is found, delete it.

00459     {
00460         Object foundObj = delete( root, key );
00461         return foundObj;
00462     } // delete

Object BinaryTree.delete NodeReference  root,
Object  key
[private]
 

This function searches a binary tree for "key" and deletes the item from the tree if it found.

The ordering of the tree is maintained (see below). If "key" is found, the Object will be returned. If "key" is not found, the function returns null.

When the node is found in the tree there are three possible cases:

  1. The node is a leaf node (no children). In this case the node can simply be unlinked from the tree and returned.
  2. The node has one child. In this case, the node is replaced by its child node.
  3. The node has two children. In this case the node is replaced by the least value from the right branch. This value is found by taking the right branch, and then walking down the left branch (see the unlink function, above). The value found this way should be the next greatest value in the tree.

00248     {
00249         Object retObj = null;
00250 
00251         if (root.ref != null) {
00252             // if (root->key > key)
00253             if (mCompare.compare(root.ref.getObj(), key) > 0) {
00254                 retObj = delete(root.ref.getLeftRef(), key);
00255             }
00256             else if (mCompare.compare(root.ref.getObj(), key) < 0) {
00257                 retObj = delete(root.ref.getRightRef(), key);
00258             }
00259             else { // the keys are equal, remove the node
00260                 Node node = null;
00261                 Node new_child = null;
00262                 int num_children = 0;
00263           
00264                 node = root.ref;
00265                 retObj = root.ref.getObj();
00266 
00267                 // Count the children of the node
00268                 if (root.ref.getLeft() != null) {
00269                     num_children++;
00270                     new_child = root.ref.getLeft();
00271                 }
00272                 if (root.ref.getRight() != null) {
00273                     num_children++;
00274                     new_child = root.ref.getRight();
00275                 }
00276 
00277                 switch (num_children) {
00278                 case 0: root.ref = null;
00279                     break;
00280                 case 1: root.ref = new_child;  // Replace the node with its child
00281                     break;
00282                 case 2: {
00283                     Node treeNode = unlink(root.ref.getRightRef());
00284 
00285                     // Make sure we're not pointing to ourselves
00286                     if (treeNode != root.ref.getRight()) {
00287                         treeNode.setRight( root.ref.getRight() );
00288                     }
00289                     // we know that treeNode is not the left node, so set the left
00290                     // reference
00291                     treeNode.setLeft( root.ref.getLeft() );
00292                     root.ref = treeNode;
00293                 }
00294                     break;
00295                 } // switch
00296                 mNodeCount--;
00297             } // keys are equal
00298         }  // root != null
00299         return retObj;
00300     } // delete

Object BinaryTree.insert Object  newObj  ) 
 

Insert an object in the tree if it is not already present.

Returns:
if the object is not found in the tree, return null. Otherwise return the object in the tree.

00435     {
00436         Object foundObj = searchAndInsert( root, newObj, true );
00437         return foundObj;
00438     } // insert

Object BinaryTree.search Object  key  ) 
 

Search for an object in the tree that compares equal to key.

Returns:
If the object is found in the tree, return a reference to the object. Otherwise return null.

00448     {
00449         Object foundObj = searchAndInsert( root, key, false );
00450         return foundObj;
00451     } // search

Object BinaryTree.searchAndInsert NodeReference  root,
Object  key,
boolean  insert
[private]
 

Recursive tree search and insert.

The tree is constructed of unique items. If an item is already present in the tree, key will not be inserted, even though insert may be true.

Parameters:
root the root of the current subtree.
key this object contains the key value being searched for.
insert if this flag is true, key will be inserted into the tree if it is not already present.
Returns:
if an object in the tree that matches key is found, return a reference to this object. Otherwise return null.

00319     {
00320         Object retObj = null;
00321 
00322         if (root.ref == null && insert) {
00323             root.ref = new Node( key );
00324             mNodeCount++;
00325         }
00326         else {  // if root.ref.getObj() > key
00327             if (mCompare.compare(root.ref.getObj(), key) > 0) {
00328                 searchAndInsert(root.ref.getLeftRef(), key, insert); // search left branch
00329             }   // if root.ref.getObj() < key
00330             else if (mCompare.compare(root.ref.getObj(), key) < 0) {
00331                 searchAndInsert(root.ref.getRightRef(), key, insert);// search right branch
00332             }
00333             else { // key == root.ref.getObj()
00334                 retObj = root.ref.getObj();
00335             }
00336         }
00337         return retObj;
00338     } // searchAndInsert

int BinaryTree.size  ) 
 

Return the number of data items (Objects) in the tree.

00465 { return mNodeCount; }

String BinaryTree.spaces int  count  )  [private]
 

Return a string consisting of count spaces.

00345     {
00346         String result = "";
00347         if (count > 0) {
00348             StringBuffer buf = new StringBuffer();
00349             for (int i = 0; i < count; i++) {
00350                 buf.append(' ');
00351             }
00352             result = buf.toString();
00353         }
00354         return result;
00355     } // spaces

Object [] BinaryTree.toArray  ) 
 

Return an ordered array of tree objects, where Object values (as determined by the Comparator object used to initialize the BinaryTree constructor) increase with the array indices (e.g., the smallest value is at index 0, the largest value is at index n.

00421     {
00422         Vector vec = new Vector();
00423         toArray( root.ref, vec );
00424         return vec.toArray();
00425     }

void BinaryTree.toArray Node  root,
Vector  vec
[private]
 

Recursively traverse the tree (using inorder tranversal) and insert the Objects from the tree into a Vector.

00405     {
00406         if (root != null) {
00407             toArray( root.getLeft(), vec );
00408             vec.add( root.getObj() );
00409             toArray( root.getRight(), vec );
00410         }
00411     } // toArray

String BinaryTree.toString  ) 
 

Return a String which contains the tree represented in "landscape" form, running down the page.

The tree children are indented from the parents to show the tree structure.

00391     {
00392         ByteArrayOutputStream bos = new ByteArrayOutputStream();
00393         PrintStream ps = new PrintStream( bos );
00394 
00395         toString(root, ps, 0);
00396         return bos.toString();
00397     } // toString

void BinaryTree.toString NodeReference  root,
PrintStream  ps,
int  indent
[private]
 

Recursively build up a "landscape" display for the tree (e.g., a tree running down the page).

When one of the children of a node is null (but not both) a null is added so that it is possible to see whether a child is a left or right child.

00365     {
00366         ps.print( spaces(indent) );
00367         ps.println( root.ref.getObj().toString() );
00368 
00369         if (root.ref.getLeft() != null) {
00370             toString( root.ref.getLeftRef(), ps, indent+4 );
00371         }
00372         else if (root.ref.getRight() != null) {
00373             ps.println( spaces(indent+4) + "null" );
00374         }
00375         
00376         if (root.ref.getRight() != null) {
00377             toString( root.ref.getRightRef(), ps, indent+4 );
00378         }
00379         else if (root.ref.getLeft() != null) {
00380             ps.println( spaces(indent+4) + "null" );
00381         }
00382     } // toString

Node BinaryTree.unlink NodeReference  root  )  [private]
 

When a value is removed from an ordered binary tree and the value has two children, it will be replaced by the next value in the right sub-branch which is greater.

This value will be the last (leaf) value in the left branch of the right branch sub-tree. The right sub-tree node is the argument to this function.

The unlink function walks down a sub-tree's left branch until it gets to the end (the leaf node). It removes the value at the end of the branch and returns it (so it can be inserted into the "hole" left by the deleted value). If the value at the end of the left branch has a right branch child, this value replaces the terminal left branch node.

Returns:
either the Node referenced by root (if root has no left branch) or the Node at the end of the left branch.

00196     {
00197         Node treeNode = null;
00198 
00199         NodeReference nodeRef;
00200         // move down the left branch, until the object pointed to by the node
00201         // reference has a null link.
00202         for (nodeRef = root; nodeRef.ref.getLeft() != null; nodeRef = nodeRef.ref.getLeftRef()) {
00203             /* nada */;
00204         }
00205 
00206         treeNode = nodeRef.ref;
00207 
00208         if (nodeRef.ref.getRight() != null) {
00209             nodeRef.ref = nodeRef.ref.getRight();
00210         }
00211         else {
00212             nodeRef.ref = null;
00213         }
00214 
00215         return treeNode;
00216     } // unlink


Member Data Documentation

Comparator BinaryTree.mCompare [private]
 

Object used to compare Objects in the tree.

int BinaryTree.mNodeCount [private]
 

Number of nodes in the binary tree.

NodeReference BinaryTree.root [private]
 

root of the binary tree


The documentation for this class was generated from the following file:
Generated on Mon Sep 1 20:49:25 2003 for BinaryTree by doxygen 1.3.3