| /* TreeMap.java -- a class providing a basic Red-Black Tree data structure, |
| mapping Object --> Object |
| Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. |
| |
| This file is part of GNU Classpath. |
| |
| GNU Classpath is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU Classpath is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Classpath; see the file COPYING. If not, write to the |
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
| 02111-1307 USA. |
| |
| As a special exception, if you link this library with other files to |
| produce an executable, this library does not by itself cause the |
| resulting executable to be covered by the GNU General Public License. |
| This exception does not however invalidate any other reasons why the |
| executable file might be covered by the GNU General Public License. */ |
| |
| |
| package java.util; |
| |
| import java.io.Serializable; |
| import java.io.ObjectOutputStream; |
| import java.io.ObjectInputStream; |
| import java.io.IOException; |
| |
| /** |
| * This class provides a red-black tree implementation of the SortedMap |
| * interface. Elements in the Map will be sorted by either a user-provided |
| * Comparator object, or by the natural ordering of the keys. |
| * |
| * The algorithms are adopted from Corman, Leiserson, |
| * and Rivest's <i>Introduction to Algorithms.</i> In other words, |
| * I cribbed from the same pseudocode as Sun. <em>Any similarity |
| * between my code and Sun's (if there is any -- I have never looked |
| * at Sun's) is a result of this fact.</em> |
| * |
| * TreeMap guarantees O(log n) insertion and deletion of elements. That |
| * being said, there is a large enough constant coefficient in front of |
| * that "log n" (overhead involved in keeping the tree |
| * balanced), that TreeMap may not be the best choice for small |
| * collections. |
| * |
| * TreeMap is a part of the JDK1.2 Collections API. Null keys are allowed |
| * only if a Comparator is used which can deal with them. Null values are |
| * always allowed. |
| * |
| * @author Jon Zeppieri |
| * @author Bryce McKinlay |
| */ |
| public class TreeMap extends AbstractMap |
| implements SortedMap, Cloneable, Serializable |
| { |
| private static final int RED = -1, |
| BLACK = 1; |
| |
| /** Sentinal node, used to avoid null checks for corner cases and make the |
| delete rebalance code simpler. Note that this must not be static, due |
| to thread-safety concerns. */ |
| transient Node nil = new Node(null, null); |
| |
| /** The root node of this TreeMap */ |
| transient Node root = nil; |
| |
| /** The size of this TreeMap */ |
| transient int size = 0; |
| |
| /** Number of modifications */ |
| transient int modCount = 0; |
| |
| /** This TreeMap's comparator, if any. */ |
| Comparator comparator = null; |
| |
| static final long serialVersionUID = 919286545866124006L; |
| |
| private static class Node extends BasicMapEntry implements Map.Entry |
| { |
| int color; |
| Node left; |
| Node right; |
| Node parent; |
| |
| Node(Object key, Object value) |
| { |
| super(key, value); |
| this.color = BLACK; |
| } |
| } |
| |
| /** |
| * Instantiate a new TreeMap with no elements, using the keys' |
| * natural ordering to sort. |
| * |
| * @see java.lang.Comparable |
| */ |
| public TreeMap() |
| { |
| } |
| |
| /** |
| * Instantiate a new TreeMap with no elements, using the provided |
| * comparator to sort. |
| * |
| * @param oComparator a Comparator object, used to sort |
| * the keys of this SortedMap |
| */ |
| public TreeMap(Comparator c) |
| { |
| comparator = c; |
| } |
| |
| /** |
| * Instantiate a new TreeMap, initializing it with all of the |
| * elements in the provided Map. The elements will be sorted |
| * using the natural ordering of the keys. |
| * |
| * @param map a Map, whose keys will be put into |
| * this TreeMap |
| * |
| * @throws ClassCastException if the keys in the provided |
| * Map do not implement |
| * Comparable |
| * |
| * @see java.lang.Comparable |
| */ |
| public TreeMap(Map map) |
| { |
| putAll(map); |
| } |
| |
| /** |
| * Instantiate a new TreeMap, initializing it with all of the |
| * elements in the provided SortedMap. The elements will be sorted |
| * using the same method as in the provided SortedMap. |
| */ |
| public TreeMap(SortedMap sm) |
| { |
| this(sm.comparator()); |
| |
| int sm_size = sm.size(); |
| Iterator itr = sm.entrySet().iterator(); |
| |
| fabricateTree(sm_size); |
| Node node = firstNode(); |
| |
| for (int i = 0; i < sm_size; i++) |
| { |
| Map.Entry me = (Map.Entry) itr.next(); |
| node.key = me.getKey(); |
| node.value = me.getValue(); |
| node = successor(node); |
| } |
| } |
| |
| public int size() |
| { |
| return size; |
| } |
| |
| public void clear() |
| { |
| modCount++; |
| root = nil; |
| // nil node could have a residual parent reference, clear it for GC. |
| nil.parent = null; |
| size = 0; |
| } |
| |
| public Object clone() |
| { |
| TreeMap copy = null; |
| try |
| { |
| copy = (TreeMap) super.clone(); |
| } |
| catch (CloneNotSupportedException x) |
| { |
| } |
| // Each instance must have a unique sentinal. |
| copy.nil = new Node(null, null); |
| copy.fabricateTree(size); |
| |
| Node node = firstNode(); |
| Node cnode = copy.firstNode(); |
| |
| while (node != nil) |
| { |
| cnode.key = node.key; |
| cnode.value = node.value; |
| node = successor(node); |
| cnode = copy.successor(cnode); |
| } |
| return copy; |
| } |
| |
| public Comparator comparator() |
| { |
| return comparator; |
| } |
| |
| public boolean containsKey(Object key) |
| { |
| return getNode(key) != nil; |
| } |
| |
| public boolean containsValue(Object value) |
| { |
| Node node = firstNode(); |
| Object currentVal; |
| |
| while (node != nil) |
| { |
| currentVal = node.getValue(); |
| |
| if (value == null ? currentVal == null : value.equals (currentVal)) |
| return true; |
| |
| node = successor(node); |
| } |
| return false; |
| } |
| |
| public Set entrySet() |
| { |
| // Create an AbstractSet with custom implementations of those methods that |
| // can be overriden easily and efficiently. |
| return new AbstractSet() |
| { |
| public int size() |
| { |
| return size; |
| } |
| |
| public Iterator iterator() |
| { |
| return new TreeIterator(TreeIterator.ENTRIES); |
| } |
| |
| public void clear() |
| { |
| TreeMap.this.clear(); |
| } |
| |
| public boolean contains(Object o) |
| { |
| if (!(o instanceof Map.Entry)) |
| return false; |
| Map.Entry me = (Map.Entry) o; |
| Node n = getNode(me.getKey()); |
| return (n != nil && me.getValue().equals(n.value)); |
| } |
| |
| public boolean remove(Object o) |
| { |
| if (!(o instanceof Map.Entry)) |
| return false; |
| Map.Entry me = (Map.Entry) o; |
| Node n = getNode(me.getKey()); |
| if (n != nil && me.getValue().equals(n.value)) |
| { |
| removeNode(n); |
| return true; |
| } |
| return false; |
| } |
| }; |
| } |
| |
| public Object firstKey() |
| { |
| if (root == nil) |
| throw new NoSuchElementException("empty"); |
| return firstNode().getKey(); |
| } |
| |
| private Node firstNode() |
| { |
| if (root == nil) |
| return nil; |
| Node node = root; |
| while (node.left != nil) |
| node = node.left; |
| return node; |
| } |
| |
| public Object lastKey() |
| { |
| if (root == nil) |
| throw new NoSuchElementException("empty"); |
| return lastNode().getKey(); |
| } |
| |
| private Node lastNode() |
| { |
| if (root == nil) |
| return nil; |
| Node node = root; |
| while (node.right != nil) |
| node = node.right; |
| return node; |
| } |
| |
| public Object get(Object key) |
| { |
| return getNode(key).value; |
| } |
| |
| /** Return the TreeMap.Node associated with KEY, or the nil node if no such |
| node exists in the tree. */ |
| private Node getNode(Object key) |
| { |
| int comparison; |
| Node current = root; |
| |
| while (current != nil) |
| { |
| comparison = compare(key, current.key); |
| if (comparison > 0) |
| current = current.right; |
| else if (comparison < 0) |
| current = current.left; |
| else |
| return current; |
| } |
| return current; |
| } |
| |
| public Set keySet() |
| { |
| // Create an AbstractSet with custom implementations of those methods that |
| // can be overriden easily and efficiently. |
| return new AbstractSet() |
| { |
| public int size() |
| { |
| return size; |
| } |
| |
| public Iterator iterator() |
| { |
| return new TreeIterator(TreeIterator.KEYS); |
| } |
| |
| public void clear() |
| { |
| TreeMap.this.clear(); |
| } |
| |
| public boolean contains(Object o) |
| { |
| return TreeMap.this.containsKey(o); |
| } |
| |
| public boolean remove(Object key) |
| { |
| Node n = getNode(key); |
| if (n == nil) |
| return false; |
| TreeMap.this.removeNode(n); |
| return true; |
| } |
| }; |
| } |
| |
| public Object put(Object key, Object value) |
| { |
| modCount++; |
| Node current = root; |
| Node parent = nil; |
| int comparison = 0; |
| |
| // Find new node's parent. |
| while (current != nil) |
| { |
| parent = current; |
| comparison = compare(key, current.key); |
| if (comparison > 0) |
| current = current.right; |
| else if (comparison < 0) |
| current = current.left; |
| else |
| { |
| // Key already in tree. |
| Object r = current.value; |
| current.value = value; |
| return r; |
| } |
| } |
| |
| // Set up new node. |
| Node n = new Node(key, value); |
| n.color = RED; |
| n.parent = parent; |
| n.left = nil; |
| n.right = nil; |
| |
| // Insert node in tree. |
| size++; |
| if (parent == nil) |
| { |
| // Special case: inserting into an empty tree. |
| root = n; |
| n.color = BLACK; |
| return null; |
| } |
| else if (comparison > 0) |
| parent.right = n; |
| else |
| parent.left = n; |
| |
| // Rebalance after insert. |
| insertFixup(n); |
| //verifyTree(); |
| return null; |
| } |
| |
| /** Maintain red-black balance after inserting a new node. */ |
| private void insertFixup(Node n) |
| { |
| // Only need to rebalance when parent is a RED node, and while at least |
| // 2 levels deep into the tree (ie: node has a grandparent). |
| while (n != root && n.parent.parent != nil && n.parent.color == RED) |
| { |
| if (n.parent == n.parent.parent.left) |
| { |
| Node uncle = n.parent.parent.right; |
| if (uncle != nil && uncle.color == RED) |
| { |
| n.parent.color = BLACK; |
| uncle.color = BLACK; |
| n.parent.parent.color = RED; |
| n = n.parent.parent; |
| } |
| else // Uncle is BLACK. |
| { |
| if (n == n.parent.right) |
| { |
| // Make n a left child. |
| n = n.parent; |
| rotateLeft(n); |
| } |
| |
| // Recolor and rotate. |
| n.parent.color = BLACK; |
| n.parent.parent.color = RED; |
| rotateRight(n.parent.parent); |
| } |
| } |
| else |
| { |
| // Mirror image of above code. |
| Node uncle = n.parent.parent.left; |
| if (uncle != nil && uncle.color == RED) |
| { |
| n.parent.color = BLACK; |
| uncle.color = BLACK; |
| n.parent.parent.color = RED; |
| n = n.parent.parent; |
| } |
| else |
| { |
| if (n == n.parent.left) |
| { |
| n = n.parent; |
| rotateRight(n); |
| } |
| n.parent.color = BLACK; |
| n.parent.parent.color = RED; |
| rotateLeft(n.parent.parent); |
| } |
| } |
| } |
| root.color = BLACK; |
| } |
| |
| public void putAll(Map m) |
| { |
| Iterator itr = m.entrySet().iterator(); |
| int msize = m.size(); |
| Map.Entry e; |
| |
| for (int i = 0; i < msize; i++) |
| { |
| e = (Map.Entry) itr.next(); |
| put(e.getKey(), e.getValue()); |
| } |
| } |
| |
| public Object remove(Object key) |
| { |
| Node n = getNode(key); |
| if (n != nil) |
| { |
| removeNode(n); |
| return n.value; |
| } |
| return null; |
| } |
| |
| // Remove node from tree. This will increment modCount and decrement size. |
| // Node must exist in the tree. |
| private void removeNode(Node node) // z |
| { |
| Node splice; // y |
| Node child; // x |
| |
| modCount++; |
| size--; |
| |
| // Find splice, the node at the position to actually remove from the tree. |
| if (node.left == nil || node.right == nil) |
| { |
| // Node to be deleted has 0 or 1 children. |
| splice = node; |
| if (node.left == nil) |
| child = node.right; |
| else |
| child = node.left; |
| } |
| else |
| { |
| // Node has 2 children. Splice is node's successor, and will be |
| // swapped with node since we can't remove node directly. |
| splice = node.right; |
| while (splice.left != nil) |
| splice = splice.left; |
| child = splice.right; |
| } |
| |
| // Unlink splice from the tree. |
| Node parent = splice.parent; |
| child.parent = parent; |
| if (parent != nil) |
| { |
| if (splice == parent.left) |
| parent.left = child; |
| else |
| parent.right = child; |
| } |
| else |
| root = child; |
| |
| // Keep track of splice's color in case it gets changed in the swap. |
| int spliceColor = splice.color; |
| |
| /* |
| if (splice != node) |
| { |
| node.key = splice.key; |
| node.value = splice.value; |
| } |
| */ |
| if (splice != node) |
| { |
| // Swap SPLICE for NODE. Some implementations optimize here by simply |
| // swapping the values, but we can't do that: if an iterator was |
| // referencing a node in its "next" field, and that node got swapped, |
| // things would get confused. |
| if (node == root) |
| { |
| root = splice; |
| } |
| else |
| { |
| if (node.parent.left == node) |
| node.parent.left = splice; |
| else |
| node.parent.right = splice; |
| } |
| splice.parent = node.parent; |
| splice.left = node.left; |
| splice.right = node.right; |
| splice.left.parent = splice; |
| splice.right.parent = splice; |
| splice.color = node.color; |
| } |
| |
| if (spliceColor == BLACK) |
| deleteFixup (child); |
| |
| //verifyTree(); |
| } |
| |
| /** Maintain red-black balance after deleting a node. */ |
| private void deleteFixup (Node node) |
| { |
| // A black node has been removed, so we need to rebalance to avoid |
| // violating the "same number of black nodes on any path" rule. If |
| // node is red, we can simply recolor it black and all is well. |
| while (node != root && node.color == BLACK) |
| { |
| if (node == node.parent.left) |
| { |
| // Rebalance left side. |
| Node sibling = node.parent.right; |
| if (sibling.color == RED) |
| { |
| sibling.color = BLACK; |
| node.parent.color = RED; |
| rotateLeft(node.parent); |
| sibling = node.parent.right; |
| } |
| |
| if (sibling.left.color == BLACK && sibling.right.color == BLACK) |
| { |
| // Case 2: Sibling has no red children. |
| sibling.color = RED; |
| // Black height has been decreased, so move up the tree and |
| // repeat. |
| node = node.parent; |
| } |
| else |
| { |
| if (sibling.right.color == BLACK) |
| { |
| // Case 3: Sibling has red left child. |
| sibling.left.color = BLACK; |
| sibling.color = RED; |
| rotateRight(sibling); |
| sibling = node.parent.right; |
| } |
| |
| // Case 4: Sibling has red right child. |
| sibling.color = sibling.parent.color; |
| sibling.parent.color = BLACK; |
| sibling.right.color = BLACK; |
| rotateLeft(node.parent); |
| node = root; // Finished. |
| } |
| } |
| else |
| { |
| // Symmetric "mirror" of left-side case. |
| Node sibling = node.parent.left; |
| if (sibling.color == RED) |
| { |
| sibling.color = BLACK; |
| node.parent.color = RED; |
| rotateRight(node.parent); |
| sibling = node.parent.left; |
| } |
| |
| if (sibling.left.color == BLACK && sibling.right.color == BLACK) |
| { |
| sibling.color = RED; |
| node = node.parent; |
| } |
| else |
| { |
| if (sibling.left.color == BLACK) |
| { |
| sibling.right.color = BLACK; |
| sibling.color = RED; |
| rotateLeft(sibling); |
| sibling = node.parent.left; |
| } |
| |
| sibling.color = sibling.parent.color; |
| sibling.parent.color = BLACK; |
| sibling.left.color = BLACK; |
| rotateRight(node.parent); |
| node = root; |
| } |
| } |
| } |
| node.color = BLACK; |
| } |
| |
| public SortedMap subMap(Object fromKey, Object toKey) |
| { |
| if (compare(fromKey, toKey) <= 0) |
| return new SubMap(fromKey, toKey); |
| else |
| throw new IllegalArgumentException("fromKey > toKey"); |
| } |
| |
| public SortedMap headMap(Object toKey) |
| { |
| return new SubMap(nil, toKey); |
| } |
| |
| public SortedMap tailMap(Object fromKey) |
| { |
| return new SubMap(fromKey, nil); |
| } |
| |
| /** Returns a "collection view" (or "bag view") of this TreeMap's values. */ |
| public Collection values() |
| { |
| // We don't bother overriding many of the optional methods, as doing so |
| // wouldn't provide any significant performance advantage. |
| return new AbstractCollection() |
| { |
| public int size() |
| { |
| return size; |
| } |
| |
| public Iterator iterator() |
| { |
| return new TreeIterator(TreeIterator.VALUES); |
| } |
| |
| public void clear() |
| { |
| TreeMap.this.clear(); |
| } |
| }; |
| } |
| |
| // Find the "highest" node which is < key. If key is nil, return last node. |
| // Note that highestLessThan is exclusive (it won't return a key which is |
| // equal to "key"), while lowestGreaterThan is inclusive, in order to be |
| // consistent with the semantics of subMap(). |
| private Node highestLessThan(Object key) |
| { |
| if (key == nil) |
| return lastNode(); |
| |
| Node last = nil; |
| Node current = root; |
| int comparison = 0; |
| |
| while (current != nil) |
| { |
| last = current; |
| comparison = compare(key, current.key); |
| if (comparison > 0) |
| current = current.right; |
| else if (comparison < 0) |
| current = current.left; |
| else /* Exact match. */ |
| return predecessor(last); |
| } |
| if (comparison <= 0) |
| return predecessor(last); |
| else |
| return last; |
| } |
| |
| // Find the "lowest" node which is >= key. If key is nil, return first node. |
| private Node lowestGreaterThan(Object key) |
| { |
| if (key == nil) |
| return firstNode(); |
| |
| Node last = nil; |
| Node current = root; |
| int comparison = 0; |
| |
| while (current != nil) |
| { |
| last = current; |
| comparison = compare(key, current.key); |
| if (comparison > 0) |
| current = current.right; |
| else if (comparison < 0) |
| current = current.left; |
| else |
| return current; |
| } |
| if (comparison > 0) |
| return successor(last); |
| else |
| return last; |
| } |
| |
| private void writeObject(ObjectOutputStream out) throws IOException |
| { |
| out.defaultWriteObject(); |
| |
| Node node = firstNode(); |
| out.writeInt(size); |
| |
| while (node != nil) |
| { |
| out.writeObject(node.key); |
| out.writeObject(node.value); |
| node = successor(node); |
| } |
| } |
| |
| private void readObject(ObjectInputStream in) |
| throws IOException, ClassNotFoundException |
| { |
| in.defaultReadObject(); |
| int size = in.readInt(); |
| putFromObjStream(in, size, true); |
| } |
| |
| private int compare(Object o1, Object o2) |
| { |
| if (comparator == null) |
| return ((Comparable) o1).compareTo(o2); |
| else |
| return comparator.compare(o1, o2); |
| } |
| |
| /* Return the node following Node, or nil if there isn't one. */ |
| private Node successor(Node node) |
| { |
| if (node.right != nil) |
| { |
| node = node.right; |
| while (node.left != nil) |
| node = node.left; |
| return node; |
| } |
| |
| Node parent = node.parent; |
| while (parent != nil && node == parent.right) |
| { |
| node = parent; |
| parent = parent.parent; |
| } |
| return parent; |
| } |
| |
| /* Return the node preceeding Node, or nil if there isn't one. */ |
| private Node predecessor(Node node) |
| { |
| if (node.left != nil) |
| { |
| node = node.left; |
| while (node.right != nil) |
| node = node.right; |
| return node; |
| } |
| |
| Node parent = node.parent; |
| while (parent != nil && node == parent.left) |
| { |
| node = parent; |
| parent = parent.parent; |
| } |
| return parent; |
| } |
| |
| /** Rotate node n to the left. */ |
| private void rotateLeft(Node node) |
| { |
| Node child = node.right; |
| |
| // Establish node.right link. |
| node.right = child.left; |
| if (child.left != nil) |
| child.left.parent = node; |
| |
| // Establish child->parent link. |
| child.parent = node.parent; |
| if (node.parent != nil) |
| { |
| if (node == node.parent.left) |
| node.parent.left = child; |
| else |
| node.parent.right = child; |
| } |
| else |
| root = child; |
| |
| // Link n and child. |
| child.left = node; |
| if (node != nil) |
| node.parent = child; |
| } |
| |
| /** Rotate node n to the right. */ |
| private void rotateRight(Node node) |
| { |
| Node child = node.left; |
| |
| // Establish node.left link. |
| node.left = child.right; |
| if (child.right != nil) |
| child.right.parent = node; |
| |
| // Establish child->parent link. |
| child.parent = node.parent; |
| if (node.parent != nil) |
| { |
| if (node == node.parent.right) |
| node.parent.right = child; |
| else |
| node.parent.left = child; |
| } |
| else |
| root = child; |
| |
| // Link n and child. |
| child.right = node; |
| if (node != nil) |
| node.parent = child; |
| } |
| |
| /* Construct a tree from sorted keys in linear time. This is used to |
| implement TreeSet's SortedSet constructor. */ |
| void putKeysLinear(Iterator keys, int count) |
| { |
| fabricateTree(count); |
| Node node = firstNode(); |
| |
| for (int i = 0; i < count; i++) |
| { |
| node.key = keys.next(); |
| node.value = Boolean.TRUE; |
| node = successor(node); |
| } |
| } |
| |
| /* As above, but load keys from an ObjectInputStream. Used by readObject() |
| methods. If "readValues" is set, entry values will also be read from the |
| stream. If not, only keys will be read. */ |
| void putFromObjStream(ObjectInputStream in, int count, boolean readValues) |
| throws IOException, ClassNotFoundException |
| { |
| fabricateTree(count); |
| Node node = firstNode(); |
| |
| for (int i = 0; i < count; i++) |
| { |
| node.key = in.readObject(); |
| if (readValues) |
| node.value = in.readObject(); |
| else |
| node.value = Boolean.TRUE; |
| node = successor(node); |
| } |
| } |
| |
| /* Construct a perfectly balanced tree consisting of n "blank" nodes. |
| This permits a tree to be generated from pre-sorted input in linear |
| time. */ |
| private void fabricateTree(int count) |
| { |
| if (count == 0) |
| return; |
| // Calculate the (maximum) depth of the perfectly balanced tree. |
| double ddepth = (Math.log (count + 1) / Math.log (2)); |
| int maxdepth = (int) Math.ceil (ddepth); |
| |
| // The number of nodes which can fit in a perfectly-balanced tree of |
| // height "depth - 1". |
| int max = (int) Math.pow (2, maxdepth - 1) - 1; |
| |
| // Number of nodes which spill over into the deepest row of the tree. |
| int overflow = (int) count - max; |
| |
| size = count; |
| // Make the root node. |
| root = new Node(null, null); |
| root.parent = nil; |
| root.left = nil; |
| root.right = nil; |
| |
| Node row = root; |
| for (int depth = 2; depth <= maxdepth; depth++) // each row |
| { |
| // Number of nodes at this depth |
| int rowcap = (int) Math.pow (2, depth - 1); |
| Node parent = row; |
| Node last = null; |
| |
| // Actual number of nodes to create in this row |
| int rowsize; |
| if (depth == maxdepth) |
| rowsize = overflow; |
| else |
| rowsize = rowcap; |
| |
| // The bottom most row of nodes is coloured red, as is every second row |
| // going up, except the root node (row 1). I'm not sure if this is the |
| // optimal configuration for the tree, but it seems logical enough. |
| // We just need to honour the black-height and red-parent rules here. |
| boolean colorRowRed = (depth % 2 == maxdepth % 2); |
| |
| int i; |
| for (i = 1; i <= rowsize; i++) // each node in row |
| { |
| Node node = new Node(null, null); |
| node.parent = parent; |
| if (i % 2 == 1) |
| parent.left = node; |
| else |
| { |
| Node nextparent = parent.right; |
| parent.right = node; |
| parent = nextparent; |
| } |
| |
| // We use the "right" link to maintain a chain of nodes in |
| // each row until the parent->child links are established. |
| if (last != null) |
| last.right = node; |
| last = node; |
| |
| if (colorRowRed) |
| node.color = RED; |
| |
| if (i == 1) |
| row = node; |
| } |
| |
| // Set nil child pointers on leaf nodes. |
| if (depth == maxdepth) |
| { |
| // leaf nodes at maxdepth-1. |
| if (parent != null) |
| { |
| if (i % 2 == 0) |
| { |
| // Current "parent" has "left" set already. |
| Node next = parent.right; |
| parent.right = nil; |
| parent = next; |
| } |
| while (parent != null) |
| { |
| parent.left = nil; |
| Node next = parent.right; |
| parent.right = nil; |
| parent = next; |
| } |
| } |
| // leaf nodes at maxdepth. |
| Node node = row; |
| Node next; |
| while (node != null) |
| { |
| node.left = nil; |
| next = node.right; |
| node.right = nil; |
| node = next; |
| } |
| } |
| } |
| } |
| |
| private class VerifyResult |
| { |
| int count; // Total number of nodes. |
| int black; // Black height/depth. |
| int maxdepth; // Maximum depth of branch. |
| } |
| |
| /* Check that red-black properties are consistent for the tree. */ |
| private void verifyTree() |
| { |
| if (root == nil) |
| { |
| System.err.println ("Verify: empty tree"); |
| if (size != 0) |
| verifyError (this, "no root node but size=" + size); |
| return; |
| } |
| VerifyResult vr = verifySub (root); |
| if (vr.count != size) |
| { |
| verifyError (this, "Tree size not consistent with actual nodes counted. " |
| + "counted " + vr.count + ", size=" + size); |
| System.exit(1); |
| } |
| System.err.println ("Verify: " + vr.count + " nodes, black height=" + vr.black |
| + ", maxdepth=" + vr.maxdepth); |
| } |
| |
| /* Recursive call to check that rbtree rules hold. Returns total node count |
| and black height of the given branch. */ |
| private VerifyResult verifySub(Node n) |
| { |
| VerifyResult vr1 = null; |
| VerifyResult vr2 = null; |
| |
| if (n.left == nil && n.right == nil) |
| { |
| // leaf node |
| VerifyResult r = new VerifyResult(); |
| r.black = (n.color == BLACK ? 1 : 0); |
| r.count = 1; |
| r.maxdepth = 1; |
| return r; |
| } |
| |
| if (n.left != nil) |
| { |
| if (n.left.parent != n) |
| verifyError(n.left, "Node's parent link does not point to " + n); |
| |
| if (n.color == RED && n.left.color == RED) |
| verifyError(n, "Red node has red left child"); |
| |
| vr1 = verifySub (n.left); |
| if (n.right == nil) |
| { |
| if (n.color == BLACK) |
| vr1.black++; |
| vr1.count++; |
| vr1.maxdepth++; |
| return vr1; |
| } |
| } |
| |
| if (n.right != nil) |
| { |
| if (n.right.parent != n) |
| verifyError(n.right, "Node's parent link does not point to " + n); |
| |
| if (n.color == RED && n.right.color == RED) |
| verifyError(n, "Red node has red right child"); |
| |
| vr2 = verifySub (n.right); |
| if (n.left == nil) |
| { |
| if (n.color == BLACK) |
| vr2.black++; |
| vr2.count++; |
| vr2.maxdepth++; |
| return vr2; |
| } |
| } |
| |
| if (vr1.black != vr2.black) |
| verifyError (n, "Black heights: " + vr1.black + "," + vr2.black + " don't match."); |
| vr1.count += vr2.count + 1; |
| vr1.maxdepth = Math.max(vr1.maxdepth, vr2.maxdepth) + 1; |
| if (n.color == BLACK) |
| vr1.black++; |
| return vr1; |
| } |
| |
| private void verifyError (Object obj, String msg) |
| { |
| System.err.print ("Verify error: "); |
| try |
| { |
| System.err.print (obj); |
| } |
| catch (Exception x) |
| { |
| System.err.print ("(error printing obj): " + x); |
| } |
| System.err.println(); |
| System.err.println (msg); |
| Thread.dumpStack(); |
| System.exit(1); |
| } |
| |
| /** |
| * Iterate over HashMap's entries. |
| * This implementation is parameterized to give a sequential view of |
| * keys, values, or entries. |
| */ |
| class TreeIterator implements Iterator |
| { |
| static final int ENTRIES = 0, |
| KEYS = 1, |
| VALUES = 2; |
| |
| // the type of this Iterator: KEYS, VALUES, or ENTRIES. |
| int type; |
| // the number of modifications to the backing Map that we know about. |
| int knownMod = TreeMap.this.modCount; |
| // The last Entry returned by a next() call. |
| Node last; |
| // The next entry that should be returned by next(). |
| Node next; |
| // The last node visible to this iterator. This is used when iterating |
| // on a SubMap. |
| Node max; |
| |
| /* Create Iterator with the supplied type: KEYS, VALUES, or ENTRIES */ |
| TreeIterator(int type) |
| { |
| this.type = type; |
| this.next = firstNode(); |
| } |
| |
| /* Construct an interator for a SubMap. Iteration will begin at node |
| "first", and stop when "max" is reached. */ |
| TreeIterator(int type, Node first, Node max) |
| { |
| this.type = type; |
| this.next = first; |
| this.max = max; |
| } |
| |
| public boolean hasNext() |
| { |
| if (knownMod != TreeMap.this.modCount) |
| throw new ConcurrentModificationException(); |
| return (next != nil); |
| } |
| |
| public Object next() |
| { |
| if (next == nil) |
| throw new NoSuchElementException(); |
| if (knownMod != TreeMap.this.modCount) |
| throw new ConcurrentModificationException(); |
| Node n = next; |
| |
| // Check limit in case we are iterating through a submap. |
| if (n != max) |
| next = successor(n); |
| else |
| next = nil; |
| |
| last = n; |
| |
| if (type == VALUES) |
| return n.value; |
| else if (type == KEYS) |
| return n.key; |
| return n; |
| } |
| |
| public void remove() |
| { |
| if (last == null) |
| throw new IllegalStateException(); |
| if (knownMod != TreeMap.this.modCount) |
| throw new ConcurrentModificationException(); |
| /* |
| Object key = null; |
| if (next != nil) |
| key = next.key; |
| */ |
| TreeMap.this.removeNode(last); |
| knownMod++; |
| /* |
| if (key != null) |
| next = getNode(key); |
| */ |
| last = null; |
| } |
| } |
| |
| class SubMap extends AbstractMap implements SortedMap |
| { |
| Object minKey; |
| Object maxKey; |
| |
| /* Create a SubMap representing the elements between minKey and maxKey |
| (inclusive). If minKey is nil, SubMap has no lower bound (headMap). |
| If maxKey is nil, the SubMap has no upper bound (tailMap). */ |
| SubMap(Object minKey, Object maxKey) |
| { |
| this.minKey = minKey; |
| this.maxKey = maxKey; |
| } |
| |
| public void clear() |
| { |
| Node current; |
| Node next = lowestGreaterThan(minKey); |
| Node max = highestLessThan(maxKey); |
| |
| if (compare(next.key, max.key) > 0) |
| // Nothing to delete. |
| return; |
| |
| do |
| { |
| current = next; |
| next = successor(current); |
| remove(current); |
| } |
| while (current != max); |
| } |
| |
| /* Check if "key" is in within the range bounds for this SubMap. |
| The lower ("from") SubMap range is inclusive, and the upper (to) bound |
| is exclusive. */ |
| private boolean keyInRange(Object key) |
| { |
| return ((minKey == nil || compare(key, minKey) >= 0) |
| && (maxKey == nil || compare(key, maxKey) < 0)); |
| } |
| |
| public boolean containsKey(Object key) |
| { |
| return (keyInRange(key) && TreeMap.this.containsKey(key)); |
| } |
| |
| public boolean containsValue(Object value) |
| { |
| Node node = lowestGreaterThan(minKey); |
| Node max = highestLessThan(maxKey); |
| Object currentVal; |
| |
| if (node == nil || max == nil || compare(node.key, max.key) > 0) |
| // Nothing to search. |
| return false; |
| |
| while (true) |
| { |
| currentVal = node.getValue(); |
| if (value == null ? currentVal == null : value.equals (currentVal)) |
| return true; |
| if (node == max) |
| return false; |
| node = successor(node); |
| } |
| } |
| |
| public Object get(Object key) |
| { |
| if (keyInRange(key)) |
| return TreeMap.this.get(key); |
| return null; |
| } |
| |
| public Object put(Object key, Object value) |
| { |
| if (keyInRange(key)) |
| return TreeMap.this.put(key, value); |
| else |
| throw new IllegalArgumentException("Key outside range"); |
| } |
| |
| public Object remove(Object key) |
| { |
| if (keyInRange(key)) |
| return TreeMap.this.remove(key); |
| else |
| return null; |
| } |
| |
| public int size() |
| { |
| Node node = lowestGreaterThan(minKey); |
| Node max = highestLessThan(maxKey); |
| |
| if (node == nil || max == nil || compare(node.key, max.key) > 0) |
| return 0; // Empty. |
| |
| int count = 1; |
| while (node != max) |
| { |
| count++; |
| node = successor(node); |
| } |
| |
| return count; |
| } |
| |
| public Set entrySet() |
| { |
| // Create an AbstractSet with custom implementations of those methods that |
| // can be overriden easily and efficiently. |
| return new AbstractSet() |
| { |
| public int size() |
| { |
| return SubMap.this.size(); |
| } |
| |
| public Iterator iterator() |
| { |
| Node first = lowestGreaterThan(minKey); |
| Node max = highestLessThan(maxKey); |
| return new TreeIterator(TreeIterator.ENTRIES, first, max); |
| } |
| |
| public void clear() |
| { |
| this.clear(); |
| } |
| |
| public boolean contains(Object o) |
| { |
| if (!(o instanceof Map.Entry)) |
| return false; |
| Map.Entry me = (Map.Entry) o; |
| Object key = me.getKey(); |
| if (!keyInRange(key)) |
| return false; |
| Node n = getNode(key); |
| return (n != nil && me.getValue().equals(n.value)); |
| } |
| |
| public boolean remove(Object o) |
| { |
| if (!(o instanceof Map.Entry)) |
| return false; |
| Map.Entry me = (Map.Entry) o; |
| Object key = me.getKey(); |
| if (!keyInRange(key)) |
| return false; |
| Node n = getNode(key); |
| if (n != nil && me.getValue().equals(n.value)) |
| { |
| removeNode(n); |
| return true; |
| } |
| return false; |
| } |
| }; |
| } |
| |
| public Comparator comparator() |
| { |
| return comparator; |
| } |
| |
| public Object firstKey() |
| { |
| Node node = lowestGreaterThan(minKey); |
| if (node == nil || !keyInRange(node.key)) |
| throw new NoSuchElementException ("empty"); |
| return node.key; |
| } |
| |
| public Object lastKey() |
| { |
| Node node = highestLessThan(maxKey); |
| if (node == nil || !keyInRange(node.key)) |
| throw new NoSuchElementException ("empty"); |
| return node.key; |
| } |
| |
| public SortedMap subMap(Object fromKey, Object toKey) |
| { |
| if (!keyInRange(fromKey) || !keyInRange(toKey)) |
| throw new IllegalArgumentException("key outside range"); |
| |
| return TreeMap.this.subMap(fromKey, toKey); |
| } |
| |
| public SortedMap headMap(Object toKey) |
| { |
| if (!keyInRange(toKey)) |
| throw new IllegalArgumentException("key outside range"); |
| |
| return TreeMap.this.subMap(minKey, toKey); |
| } |
| |
| public SortedMap tailMap(Object fromKey) |
| { |
| if (!keyInRange(fromKey)) |
| throw new IllegalArgumentException("key outside range"); |
| |
| return TreeMap.this.subMap(fromKey, maxKey); |
| } |
| } |
| } |