// CSE 373, Winter 2013 // Each TreeSet object represents a Set storing a collection of unique objects as // its elements. A Set does not allow duplicates to be added. // class invariant: nodes are always kept in proper BST (left-to-right) sorted order. import java.util.NoSuchElementException; public class TreeSet> implements Set { private TreeNode root; private int size; // Constructs an empty set. public TreeSet() { root = null; size = 0; } // Adds the given value to this set, if it was not already in the set. // If the element is already a member of this set, adding it again has no effect. public void add(E value) { root = add(root, value); } // private recursive helper for add // uses the "x = change(x)" pattern: // pass in current state of root // return out desired new state of root private TreeNode add(TreeNode node, E value) { if (node == null) { node = new TreeNode(value); // reached dead end; put new node here size++; } else if (value.compareTo(node.data) > 0) { node.right = add(node.right, value); fixHeight(node); } else if (value.compareTo(node.data) < 0) { node.left = add(node.left, value); fixHeight(node); } // else a duplicate; do nothing return node; } public void booyah() { root = rightRotate(root); } private TreeNode rightRotate(TreeNode oldParent) { TreeNode orphan = oldParent.left.right; TreeNode newParent = oldParent.left; newParent.right = oldParent; oldParent.left = orphan; fixHeight(oldParent); fixHeight(newParent); return newParent; } private TreeNode leftRotate(TreeNode oldParent) { TreeNode orphan = oldParent.right.left; TreeNode newParent = oldParent.right; newParent.left = oldParent; oldParent.right = orphan; fixHeight(oldParent); fixHeight(newParent); return newParent; } // Returns true if this set contains the given element value. public boolean contains(E value) { return contains(root, value); } // private recursive helper for contains private boolean contains(TreeNode node, E value) { if (node == null) { return false; } else if (value.compareTo(node.data) > 0) { return contains(node.right, value); } else if (value.compareTo(node.data) < 0) { return contains(node.left, value); } else { // value.equals(root.data); found it! return true; } } // Returns the minimum value in this set. // Throws a NoSuchElementException if this set is empty. public E getMin() { if (root == null) { throw new NoSuchElementException("empty tree"); } return getMin(root); } // private recursive helper for getMin private E getMin(TreeNode node) { if (node.left == null) { return node.data; } else { return getMin(node.left); } } // Returns true if this set does not contain any elements. public boolean isEmpty() { return size == 0; } // Prints all elements of this tree in a left-to-right order (in-order) traversal. public void print() { print(root); } // private recursive helper for print private void print(TreeNode node) { if (node != null) { print(node.left); System.out.println(node.data + " " + node.height); print(node.right); } // implicit base case: else do nothing } // Removes the given value from this set, if it is found in this set. // If the element is not found, calling this method has no effect. public void remove(E value) { root = remove(root, value); } // private recursive helper for remove private TreeNode remove(TreeNode node, E value) { if (node == null) { // nothing here; do nothing? } else if (value.compareTo(node.data) < 0) { node.left = remove(node.left, value); } else if (value.compareTo(node.data) > 0) { node.right = remove(node.right, value); } else { // (value == root.data) // found it! remove now. size--; if (node.left == null && node.right == null) { // leaf node = null; } else if (node.right == null) { // only left child node = node.left; } else if (node.left == null) { // only right child node = node.right; } else { // hard case: two children; replace me with min from my right E rightMin = getMin(node.right); node.right = remove(node.right, rightMin); node.data = rightMin; } } return node; } // Returns the number of elements in this set. public int size() { return size; } private void fixHeight(TreeNode node) { if (node != null) { // larger of L/R + 1 int left = 0; if (node.left != null) { left = node.left.height; } int right = 0; if (node.right != null) { right = node.right.height; } node.height = Math.max(left, right) + 1; } } // Each TreeNode object stores a single node of a binary tree. // The class has just public data fields and constructors. // This version of our code places the node as an inner class. private class TreeNode { public E data; // data stored at this node public int height; public TreeNode left; // reference to left subtree public TreeNode right; // reference to right subtree // Constructs a leaf node with the given data. public TreeNode(E data) { this(data, null, null); this.height = 1; } // Constructs a leaf or branch node with the given data and links. public TreeNode(E data, TreeNode left, TreeNode right) { this.data = data; this.left = left; this.right = right; } } }