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. |
|
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 |
|
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 |
|
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:
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 |
|
Insert an object in the tree if it is not already present.
00435 { 00436 Object foundObj = searchAndInsert( root, newObj, true ); 00437 return foundObj; 00438 } // insert |
|
Search for an object in the tree that compares equal to key.
00448 { 00449 Object foundObj = searchAndInsert( root, key, false ); 00450 return foundObj; 00451 } // search |
|
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.
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 |
|
Return the number of data items (Objects) in the tree.
00465 { return mNodeCount; } |
|
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 |
|
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.
|
|
Recursively traverse the tree (using inorder tranversal) and insert the Objects from the tree into a Vector.
|
|
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 |
|
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 |
|
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.
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 |
|
Object used to compare Objects in the tree.
|
|
Number of nodes in the binary tree.
|
|
root of the binary tree
|