package class9_3_BinarySearchTree_withRemove; import edu.msoe.se1010.winPlotter.WinPlotter; import java.util.Collection; import java.util.Iterator; import java.util.Set; /** * This class is a super-cool combination * of a SortedArrayList and a LinkedList. * * Like the SortedArrayList, the elements are always sorted. * Like the LinkedList, once we find where something should be, * we can insert it in O(1) time just by editing a few links. * * @param the type of the contained obects */ public class BinarySearchTree> extends Object implements Set { private Node root; private class Node { private Node left; private Node right; private E value; private Node(Node left, Node right, E value) { this.left = left; this.right = right; this.value = value; } } public boolean isEmpty() { return root == null; } public int size() { return size(root); } private int size(Node current) { if(current == null) { return 0; } else { return 1 + size(current.left) + size(current.right); } } public boolean add(E e) { // E value = root.value; // if(value.compareTo(e) < 0) /*...*/; if(root == null) { root = new Node(null, null, e); } else { add(root, e); } return true; // TODO: Should return false if present. } /** * * @param subRoot root of sub-tree (MUST NOT BE NULL) * @param e objce t to add */ private void add(Node subRoot, E e) { if(e.compareTo(subRoot.value) < 0) { if(subRoot.left == null) { subRoot.left = new Node(null, null, e); } else { add(subRoot.left, e); } } else if(e.compareTo(subRoot.value) > 0) { if(subRoot.right == null) { subRoot.right = new Node(null, null, e); } else { add(subRoot.right, e); } } else { System.err.println("Warning: Replacing existing node"); System.err.println("(Duplicate add)"); subRoot.value = e; } } /** * Does NOT rebalance. (Of course, neither does add...) * * Removes the specified element from this set if it is present * (optional operation). More formally, removes an element e * such that * (o==null ? e==null : o.equals(e)), if * this set contains such an element. Returns true if this set * contained the element (or equivalently, if this set changed as a * result of the call). (This set will not contain the element once the * call returns.) * * @param o object to be removed from this set, if present * @return true if this set contained the specified element * @throws ClassCastException if the type of the specified element * is incompatible with this set * (optional) * @throws NullPointerException if the specified element is null and this * set does not permit null elements * (optional) * @throws UnsupportedOperationException if the remove operation * is not supported by this set */ @Override public boolean remove(Object o) { if(o == null) { throw new NullPointerException("This tree doesn't allow null elements. Null search key provided."); } E e; try { e = (E)o; } catch (ClassCastException ex) { return false; } if(root == null) { return false; } // find node. if(root.value.equals(e)) { throw new UnsupportedOperationException("I don't remove the root -- but it is similar to other cases."); } // Edge cases are handled. // No more early returns after this point in the method. // Find the node. But don't walk off of the parent. // preconditions on loop: current points to a parent of the node, if the node is in the tree. // current is not null, and does not point to a node equal to the target. Node current = root; while((e.compareTo(current.value) < 0 && current.left != null && !current.left.value.equals(e)) || (e.compareTo(current.value) >= 0 && current.right != null && !current.right.value.equals(e))) { if(e.compareTo(current.value) < 0) { current = current.left; } else { current = current.right; } } boolean isFound = true; if(e.compareTo(current.value) < 0) { throw new UnsupportedOperationException("I don't remove a node that is on the left of it's parent. But this case is symmetric with the right."); } else { if(current.right == null) { isFound = false; } else { /* Now we remove the node! */ // easy cases Node parent = current; Node target = parent.right; // TODO: Complete } } return isFound; } public E find(E e) { return find(root,e).value; } /** * Returns true if this set contains the specified element. * More formally, returns true if and only if this set * contains an element e such that * (o==null ? e==null : o.equals(e)). * * @param o element whose presence in this set is to be tested * @return true if this set contains the specified element * @throws ClassCastException if the type of the specified element * is incompatible with this set * (optional) * @throws NullPointerException if the specified element is null and this * set does not permit null elements * (optional) */ @Override public boolean contains(Object o) { E e; try { e = (E)o; } catch (ClassCastException ex) { return false; } return find(root,e)!=null; } private Node find(Node subRoot, E e) { if(subRoot == null) { return null; } else if(e.compareTo(subRoot.value) == 0) { return subRoot; } if(e.compareTo(root.value) < 0) { return find(root.left,e); } else { return find(root.right,e); } } public void print() { printTree(root, 0); } private void printTree(Node current, int depth) { if(current != null) { printTree(current.left,depth+1); for(int i=0;i iterator() { return null; } /** * Returns an array containing all of the elements in this set. * If this set makes any guarantees as to what order its elements * are returned by its iterator, this method must return the * elements in the same order. *

*

The returned array will be "safe" in that no references to it * are maintained by this set. (In other words, this method must * allocate a new array even if this set is backed by an array). * The caller is thus free to modify the returned array. *

*

This method acts as bridge between array-based and collection-based * APIs. * * @return an array containing all the elements in this set */ @Override public Object[] toArray() { return new Object[0]; } /** * Returns an array containing all of the elements in this set; the * runtime type of the returned array is that of the specified array. * If the set fits in the specified array, it is returned therein. * Otherwise, a new array is allocated with the runtime type of the * specified array and the size of this set. *

*

If this set fits in the specified array with room to spare * (i.e., the array has more elements than this set), the element in * the array immediately following the end of the set is set to * null. (This is useful in determining the length of this * set only if the caller knows that this set does not contain * any null elements.) *

*

If this set makes any guarantees as to what order its elements * are returned by its iterator, this method must return the elements * in the same order. *

*

Like the {@link #toArray()} method, this method acts as bridge between * array-based and collection-based APIs. Further, this method allows * precise control over the runtime type of the output array, and may, * under certain circumstances, be used to save allocation costs. *

*

Suppose x is a set known to contain only strings. * The following code can be used to dump the set into a newly allocated * array of String: *

*

     *     String[] y = x.toArray(new String[0]);
* * Note that toArray(new Object[0]) is identical in function to * toArray(). * * @param a the array into which the elements of this set are to be * stored, if it is big enough; otherwise, a new array of the same * runtime type is allocated for this purpose. * @return an array containing all the elements in this set * @throws ArrayStoreException if the runtime type of the specified array * is not a supertype of the runtime type of every element in this * set * @throws NullPointerException if the specified array is null */ @Override public T[] toArray(T[] a) { return null; } /** * Returns true if this set contains all of the elements of the * specified collection. If the specified collection is also a set, this * method returns true if it is a subset of this set. * * @param c collection to be checked for containment in this set * @return true if this set contains all of the elements of the * specified collection * @throws ClassCastException if the types of one or more elements * in the specified collection are incompatible with this * set * (optional) * @throws NullPointerException if the specified collection contains one * or more null elements and this set does not permit null * elements * (optional), * or if the specified collection is null * @see #contains(Object) */ @Override public boolean containsAll(Collection c) { return false; } /** * Adds all of the elements in the specified collection to this set if * they're not already present (optional operation). If the specified * collection is also a set, the addAll operation effectively * modifies this set so that its value is the union of the two * sets. The behavior of this operation is undefined if the specified * collection is modified while the operation is in progress. * * @param c collection containing elements to be added to this set * @return true if this set changed as a result of the call * @throws UnsupportedOperationException if the addAll operation * is not supported by this set * @throws ClassCastException if the class of an element of the * specified collection prevents it from being added to this set * @throws NullPointerException if the specified collection contains one * or more null elements and this set does not permit null * elements, or if the specified collection is null * @throws IllegalArgumentException if some property of an element of the * specified collection prevents it from being added to this set * @see #add(Object) */ @Override public boolean addAll(Collection c) { return false; } /** * Retains only the elements in this set that are contained in the * specified collection (optional operation). In other words, removes * from this set all of its elements that are not contained in the * specified collection. If the specified collection is also a set, this * operation effectively modifies this set so that its value is the * intersection of the two sets. * * @param c collection containing elements to be retained in this set * @return true if this set changed as a result of the call * @throws UnsupportedOperationException if the retainAll operation * is not supported by this set * @throws ClassCastException if the class of an element of this set * is incompatible with the specified collection * (optional) * @throws NullPointerException if this set contains a null element and the * specified collection does not permit null elements * (optional), * or if the specified collection is null * @see #remove(Object) */ @Override public boolean retainAll(Collection c) { return false; } /** * Removes from this set all of its elements that are contained in the * specified collection (optional operation). If the specified * collection is also a set, this operation effectively modifies this * set so that its value is the asymmetric set difference of * the two sets. * * @param c collection containing elements to be removed from this set * @return true if this set changed as a result of the call * @throws UnsupportedOperationException if the removeAll operation * is not supported by this set * @throws ClassCastException if the class of an element of this set * is incompatible with the specified collection * (optional) * @throws NullPointerException if this set contains a null element and the * specified collection does not permit null elements * (optional), * or if the specified collection is null * @see #remove(Object) * @see #contains(Object) */ @Override public boolean removeAll(Collection c) { return false; } /** * Removes all of the elements from this set (optional operation). * The set will be empty after this call returns. * * @throws UnsupportedOperationException if the clear method * is not supported by this set */ @Override public void clear() { } }