/** * A non-balancing binary search tree implementation. */ public class BinarySearchTree> { private BinaryTree root; public BinarySearchTree() { root = null; } public BinaryTree getRoot() { return root; } // Return either the "highest" node with the given value, or // the node to which the value should be added as a child private BinaryTree locate(BinaryTree curNode, T target) { T curValue = curNode.value(); if (curValue.equals(target)) { // found at this node - done return curNode; } BinaryTree child; if (curValue.compareTo(target) < 0) { // look right child = curNode.right(); } else { // look left child = curNode.left(); } if (child == null) { // value not in tree return curNode; } // arrived at another subtree node, recurse return locate(child, target); } // search the BST for the given value public boolean contains(T value) { if (root == null) { // empty BST return false; } BinaryTree node = locate(root, value); return node.value().equals(value); } // add the given value to the BST public void add(T newValue) { BinaryTree newNode = new BinaryTree(newValue); if (root == null) { root = newNode; } else { BinaryTree insertLocation = locate(root, newValue); if (insertLocation.value().equals(newValue)) { // duplicate value - insert into left subtree (arbitrarily chosen) if (insertLocation.left() == null) { // start the left subtree insertLocation.setLeft(newNode); } else { // add as the largest value of the existing left subtree predecessor(insertLocation).setRight(newNode); } } else if (insertLocation.value().compareTo(newValue) < 0) { // not a duplicate value, add as right child insertLocation.setRight(newNode); } else { // not a duplicate value, add as left child insertLocation.setLeft(newNode); } } } // get node with the largest value in the left subtree of root private BinaryTree predecessor(BinaryTree root) { BinaryTree finger = root.left(); while (finger.right() != null) { finger = finger.right(); } return finger; } // remove top node (root) of some (sub)tree, reconnect the tree, // and return the new root of the tree private BinaryTree removeTop(BinaryTree top) { BinaryTree left = top.left(); BinaryTree right = top.right(); // disconnect the top from its children top.setLeft(null); top.setRight(null); // case 1: no left subtree - remaining tree is just right if (left == null) { return right; } // case 2: no right subtree - remaining tree is just left if (right == null) { return left; } // case 3: left node has no right subtree // "slide up" the left side of the tree if (left.right() == null) { left.setRight(right); return left; } // case 4 (general case) // start at left subtree, walk all the way right BinaryTree parent = left; BinaryTree pred = left.right(); while (pred.right() != null) { parent = pred; pred = pred.right(); } // newly chosen root (far-right) has no right subtree but might have left // left subtree takes the place of this node parent.setRight(pred.left()); // now pred becomes the new root pred.setLeft(left); pred.setRight(right); return pred; } // remove the given item from the BST and return if successful. public boolean remove(T item) { if (root == null) { return false; } BinaryTree node = locate(root, item); if (!node.value().equals(item)) { // value not in BST, nothing to do return false; } if (node == root) { // delete the root of the entire BST root = removeTop(root); } else if (node.parent().left() == node) { // node is a left child node.parent().setLeft(removeTop(node)); } else { // node is a right child node.parent().setRight(removeTop(node)); } return true; } }