package net.datastructures; import java.util.Comparator; import java.util.Iterator; /** * Realization of a map by means of a binary search tree. * @author Michael Goodrich, Eric Zamore */ //begin#fragment BinarySearchTree // Realization of a map by means of a binary search tree public class BinarySearchTreeMap extends LinkedBinaryTree> implements Map { //end#fragment BinarySearchTree // Instance variables: //begin#fragment BinarySearchTree protected Comparator C; // comparator protected Position> actionPos; // insert node or removed node's parent protected int numEntries = 0; // number of entries /** Creates a BinarySearchTreeMap with a default comparator. */ public BinarySearchTreeMap() { C = new DefaultComparator(); addRoot(null); } //end#fragment BinarySearchTree /** Creates a BinarySearchTreeMap with the given comparator. */ //begin#fragment BinarySearchTree public BinarySearchTreeMap(Comparator c) { C = c; addRoot(null); } /** Nested class for location-aware binary search tree entries */ protected static class BSTEntry implements Entry { protected K key; protected V value; protected Position> pos; BSTEntry() { /* default constructor */ } BSTEntry(K k, V v, Position> p) { key = k; value = v; pos = p; } public K getKey() { return key; } public V getValue() { return value; } public Position> position() { return pos; } } //end#fragment BinarySearchTree // Auxiliary methods: //begin#fragment BinarySearchTree /** Extracts the key of the entry at a given node of the tree. */ protected K key(Position> position) { return position.element().getKey(); } /** Extracts the value of the entry at a given node of the tree. */ protected V value(Position> position) { return position.element().getValue(); } /** Extracts the entry at a given node of the tree. */ protected Entry entry(Position> position) { return position.element(); } //end#fragment BinarySearchTree //begin#fragment BinarySearchTree2 /** Replaces an entry with a new entry (and reset the entry's location) */ protected V replaceEntry(Position > pos, Entry ent) { ((BSTEntry) ent).pos = pos; return replace(pos, ent).getValue(); } /** Checks whether a given key is valid. */ protected void checkKey(K key) throws InvalidKeyException { if(key == null) // just a simple test for now throw new InvalidKeyException("null key"); } /** Checks whether a given entry is valid. */ protected void checkEntry(Entry ent) throws InvalidEntryException { if(ent == null || !(ent instanceof BSTEntry)) throw new InvalidEntryException("invalid entry"); } /** Auxiliary method for inserting an entry at an external node */ protected Entry insertAtExternal(Position> v, Entry e) { expandExternal(v,null,null); replace(v, e); numEntries++; return e; } /** Auxiliary method for removing an external node and its parent */ protected void removeExternal(Position> v) { removeAboveExternal(v); numEntries--; } /** Auxiliary method used by get, put, and remove. */ protected Position> treeSearch(K key, Position> pos) { if (isExternal(pos)) return pos; // key not found; return external node else { K curKey = key(pos); int comp = C.compare(key, curKey); if (comp < 0) return treeSearch(key, left(pos)); // search left subtree else if (comp > 0) return treeSearch(key, right(pos)); // search right subtree return pos; // return internal node where key is found } } //end#fragment BinarySearchTree2 /** Adds to L all entries in the subtree rooted at v having keys * equal to k. */ //begin#fragment BinarySearchTree3 // methods of the map ADT //end#fragment BinarySearchTree3 /** Returns the number of entries in the tree. */ //begin#fragment BinarySearchTree3 public int size() { return numEntries; } //end#fragment BinarySearchTree3 /** Returns whether the tree is empty. */ //begin#fragment BinarySearchTree3 public boolean isEmpty() { return size() == 0; } //end#fragment BinarySearchTree3 /** * Returns the value of the entry containing the given key. Returns * null if no such entry exists. */ //begin#fragment BinarySearchTree3 public V get(K key) throws InvalidKeyException { checkKey(key); // may throw an InvalidKeyException Position> curPos = treeSearch(key, root()); actionPos = curPos; // node where the search ended if (isInternal(curPos)) return value(curPos); return null; } //end#fragment BinarySearchTree3 /** * If there is an entry with the specified key, replaces the value of * this entry with the specified value and returns the old value. Else, * adds a new entry with the specified key and value and returns null. */ //begin#fragment BinarySearchTree3 public V put(K k, V x) throws InvalidKeyException { checkKey(k); // may throw an InvalidKeyException Position> insPos = treeSearch(k, root()); BSTEntry e = new BSTEntry(k, x, insPos); actionPos = insPos; // node where the entry is being inserted if (isExternal(insPos)) { // we need a new node, key is new insertAtExternal(insPos, e).getValue(); return null; } return replaceEntry(insPos, e); // key already exists } //end#fragment BinarySearchTree3 /** * If there is an entry with the specified key, removes this entry and * returns its value. Else, returns null. */ //begin#fragment BinarySearchTree3 public V remove(K k) throws InvalidKeyException { checkKey(k); // may throw an InvalidKeyException Position> remPos = treeSearch(k, root()); if (isExternal(remPos)) return null; // key not found Entry toReturn = entry(remPos); // old entry if (isExternal(left(remPos))) remPos = left(remPos); // left easy case else if (isExternal(right(remPos))) remPos = right(remPos); // right easy case else { // entry is at a node with internal children Position> swapPos = remPos; // find node for moving entry remPos = right(swapPos); do remPos = left(remPos); while (isInternal(remPos)); replaceEntry(swapPos, (Entry) parent(remPos).element()); } actionPos = sibling(remPos); // sibling of the leaf to be removed removeExternal(remPos); return toReturn.getValue(); } //end#fragment BinarySearchTree3 /** Returns an iterable object containing all keys in the tree. */ public Iterable keySet() { PositionList keys = new NodePositionList(); Iterable>> positer = positions(); for (Position> cur: positer) if (isInternal(cur)) keys.addLast(key(cur)); return keys; } /** Returns an iterable object containing all values in the tree. */ public Iterable values() { PositionList vals = new NodePositionList(); Iterable>> positer = positions(); for (Position> cur: positer) if (isInternal(cur)) vals.addLast(value(cur)); return vals; } /** Returns an iterable object containing all entries in the tree. */ public Iterable> entrySet() { PositionList> entries = new NodePositionList>(); Iterable>> positer = positions(); for (Position> cur: positer) if (isInternal(cur)) entries.addLast(cur.element()); return entries; } /** * Performs a tri-node restructuring. Assumes the nodes are in one * of following configurations: * *
   *          z=c       z=c        z=a         z=a
   *         /  \      /  \       /  \        /  \
   *       y=b  t4   y=a  t4    t1  y=c     t1  y=b
   *      /  \      /  \           /  \         /  \
   *    x=a  t3    t1 x=b        x=b  t4       t2 x=c
   *   /  \          /  \       /  \             /  \
   *  t1  t2        t2  t3     t2  t3           t3  t4
   * 
* @return the new root of the restructured subtree */ protected Position> restructure(Position> x) { BTPosition> a, b, c, t1, t2, t3, t4; Position> y = parent(x); // assumes x has a parent Position> z = parent(y); // assumes y has a parent boolean xLeft = (x == left(y)); boolean yLeft = (y == left(z)); BTPosition> xx = (BTPosition>)x, yy = (BTPosition>)y, zz = (BTPosition>)z; if (xLeft && yLeft) { a = xx; b = yy; c = zz; t1 = a.getLeft(); t2 = a.getRight(); t3 = b.getRight(); t4 = c.getRight(); } else if (!xLeft && yLeft) { a = yy; b = xx; c = zz; t1 = a.getLeft(); t2 = b.getLeft(); t3 = b.getRight(); t4 = c.getRight(); } else if (xLeft && !yLeft) { a = zz; b = xx; c = yy; t1 = a.getLeft(); t2 = b.getLeft(); t3 = b.getRight(); t4 = c.getRight(); } else { // right-right a = zz; b = yy; c = xx; t1 = a.getLeft(); t2 = b.getLeft(); t3 = c.getLeft(); t4 = c.getRight(); } // put b at z's place if (isRoot(z)) { root = b; b.setParent(null); } else { BTPosition> zParent = (BTPosition>)parent(z); if (z == left(zParent)) { b.setParent(zParent); zParent.setLeft(b); } else { // z was a right child b.setParent(zParent); zParent.setRight(b); } } // place the rest of the nodes and their children b.setLeft(a); a.setParent(b); b.setRight(c); c.setParent(b); a.setLeft(t1); t1.setParent(a); a.setRight(t2); t2.setParent(a); c.setLeft(t3); t3.setParent(c); c.setRight(t4); t4.setParent(c); // Reset the location-aware entries ((BSTEntry) a.element()).pos = a; ((BSTEntry) b.element()).pos = b; ((BSTEntry) c.element()).pos = c; return b; // the new root of this subtree } //begin#fragment BinarySearchTree3 } //end#fragment BinarySearchTree3