// Represents a set of elements. When accessed, elements // will be returned in their "natural ordering". import java.util.NoSuchElementException; public class TreeSet> implements Set { private TreeNode overallRoot; // Constructs an empty TreeSet public TreeSet() { overallRoot = null; } // Adds the given value to this TreeSet. Returns true if the set was modified // and false if the value was already contained in this set. public boolean add(E value) { if (contains(value)) { return false; } overallRoot = add(overallRoot, value); return true; } // Adds the given value to the BST starting at the given root. // Post: the tree is still a valid BST private TreeNode add(TreeNode root, E value) { if (root == null) { root = new TreeNode(value); } else if (value.compareTo(root.data) < 0) { root.left = add(root.left, value); } else if (value.compareTo(root.data) > 0) { root.right = add(root.right, value); } return root; } // Removes the given value to this TreeSet. Returns true if the set was modified // and false if the value was not contained in this set. public boolean remove(E value) { if (!contains(value)) { return false; } overallRoot = remove(overallRoot, value); return true; } // Removes the given value from the given subtree private TreeNode remove(TreeNode root, E value) { if (root != null) { if (value.compareTo(root.data) < 0) { root.left = remove(root.left, value); } else if (value.compareTo(root.data) > 0) { root.right = remove(root.right, value); } else { // found it! root = replace(root); } } return root; } // Returns a binary search tree that is the tree of the given root // with the top node removed. private TreeNode replace(TreeNode root) { if (root.left == null && root.right == null) { root = null; } else if (root.right == null) { // left child only root = root.left; } else if (root.left == null) { // right child only; root = root.right; } else { // Find the smallest value in the right subtree TreeNode newRoot = getMinNode(root.right); // is a leaf node newRoot.left = root.left; // remove the new root from the original tree at the right, set this right to // that. newRoot.right = remove(root.right, newRoot.data); root = newRoot; } return root; } // Returns true if the value is in this set, false otherwise. public boolean contains(E value) { return contains(overallRoot, value); } // Returns true if the value is in the tree starting at the // specified root, false otherwise. private boolean contains(TreeNode root, E value) { if (root == null) { return false; } else if (root.data.compareTo(value) == 0) { return true; } else if (value.compareTo(root.data) < 0) { return contains(root.left, value); } else { return contains(root.right, value); } } // Returns the number of elements in this set. public int size() { return size(overallRoot); } // Returns the number of nodes in the subtree with root as its root node. private int size(TreeNode root) { if (root == null) { return 0; } else { return 1 + size(root.left) + size(root.right); } } // Returns true if there are no elements in this set, false // otherwise. public boolean isEmpty() { return size() == 0; } // Returns the minimum value from this set. // Throws a NoSuchElementException if the set is empty. public E getMin() { if (isEmpty()) { throw new NoSuchElementException(); } return getMinNode(overallRoot).data; } // Returns the minimum value from the tree with the given root. // Pre: root is not null private TreeNode getMinNode(TreeNode root) { if (root.left == null) { return root; } else { return getMinNode(root.left); } } // Returns a comma-separated list of the elements in this set // in sorted order. public String toString() { if (overallRoot == null) { return "[]"; } else { String contents = toString(overallRoot); return "[" + contents.substring(0, contents.length() - 2) + "]"; } } // Returns a String of the elements in the tree at the given root. private String toString(TreeNode root) { if (root == null) { return ""; } else { return toString(root.left) + root.data + ", " + toString(root.right); } } // A class that represents a single node in the tree private static class TreeNode { public E data; // data stored at this node 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); } // 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; } } }