// CSE 143, Autumn 2013 // A BinarySearchTree object represents an entire binary search tree of ints. // class invariant: // left sub tree values are less than the root // right sub tree values are greater than the root import java.util.*; public class BinarySearchTree { private IntTreeNode overallRoot; // Constructs an empty binary tree public BinarySearchTree() { overallRoot = null; } // Constructs a binary tree with the given node as its root. public BinarySearchTree(IntTreeNode overallRoot) { this.overallRoot = overallRoot; } // Prints all elements of this tree in left to right order. public void print() { print(overallRoot); } // Prints a portion of the overall tree private void print(IntTreeNode root) { // implicit base case: if null, do nothing if(root != null) { print(root.left); // print my left sub-tree System.out.print(root.data + " "); // print myself print(root.right); // print my right sub-tree } } // Returns true if the overall tree contains the given target value, // false otherwise public boolean contains(int target) { return contains(overallRoot, target); } // Returns true if a portion of the overall tree contains the given // target value, false otherwise. private boolean contains(IntTreeNode root, int target) { if(root == null) { return false; } else if(root.data == target) { return true; } else if (root.data > target) { return contains(root.left, target); } else { return contains(root.right, target); } } // Adds the value to the tree such that sorted BST order is maintained public void add(int value) { overallRoot = add(overallRoot, value); } // Adds the value to the given subtree. Does not add duplicates. // A node's initial state is passed in and it modified // state is returned. This is the x = change(x) pattern and // it allows attaching new nodes to the tree. private IntTreeNode add(IntTreeNode root, int value) { if(root == null) { root = new IntTreeNode(value); } else if (root.data > value) { root.left = add(root.left, value); } else if (root.data < value) { root.right = add(root.right, value); } return root; } // Returns the smallest value in the tree // Throws NoSuchElementException if tree is empt public int getMin() { if(overallRoot == null) { throw new NoSuchElementException(); } return getMin(overallRoot); } // Returns the smallest value in the given subtree private int getMin(IntTreeNode root) { if(root.left == null) { return root.data; } return getMin(root.left); } // Removes the given value if it is in the tree public void remove (int value) { overallRoot = remove(overallRoot, value); } // Removes the given value if it is in the subtree private IntTreeNode remove(IntTreeNode root, int value) { if(root == null) { return null; } else if(root.data > value) { root.left = remove(root.left, value); } else if(root.data < value) { root.right = remove(root.right, value); } else { // found what we want to remove if(root.right == null) { // left subtree only or leaf node return root.left; } else if(root.left == null) { // right subtree only return root.right; } else { // left and right subtrees root.data = getMin(root.right); root.right = remove(root.right, root.data); } } return root; } }