sclass LogNArray extends RandomAccessAbstractList { private transient Entry root; /** * The number of entries in the tree */ //private transient int size = 0; /** * The number of structural modifications to the tree. */ private transient int modCount = 0; // Query Operations public int size() { ret root == null ? 0 : root.size; } public bool contains(Object value) { for (Entry e = getFirstEntry(); e != null; e = successor(e)) if (valEquals(value, e.value)) return true; return false; } public A get(Object key) { Entry p = getEntry(key); return (p==null ? null : p.value); } public Int firstKey() { return key(getFirstEntry()); } public Int lastKey() { return key(getLastEntry()); } final Entry getEntry(Object key) { // Offload comparator-based version for sake of performance if (comparator != null) return getEntryUsingComparator(key); if (key == null) throw new NullPointerException(); @SuppressWarnings("unchecked") Comparable k = (Comparable) key; Entry p = root; while (p != null) { int cmp = k.compareTo(p.key); if (cmp < 0) p = p.left; else if (cmp > 0) p = p.right; else return p; } return null; } /** * Version of getEntry using comparator. Split off from getEntry * for performance. (This is not worth doing for most methods, * that are less dependent on comparator performance, but is * worthwhile here.) */ final Entry getEntryUsingComparator(Object key) { @SuppressWarnings("unchecked") Int k = (Int) key; Comparator cpr = comparator; if (cpr != null) { Entry p = root; while (p != null) { int cmp = cpr.compare(k, p.key); if (cmp < 0) p = p.left; else if (cmp > 0) p = p.right; else return p; } } return null; } /** * Gets the entry corresponding to the specified key; if no such entry * exists, returns the entry for the least key greater than the specified * key; if no such entry exists (i.e., the greatest key in the Tree is less * than the specified key), returns {@code null}. */ final Entry getCeilingEntry(Int key) { Entry p = root; while (p != null) { int cmp = compare(key, p.key); if (cmp < 0) { if (p.left != null) p = p.left; else return p; } else if (cmp > 0) { if (p.right != null) { p = p.right; } else { Entry parent = p.parent; Entry ch = p; while (parent != null && ch == parent.right) { ch = parent; parent = parent.parent; } return parent; } } else return p; } return null; } /** * Gets the entry corresponding to the specified key; if no such entry * exists, returns the entry for the greatest key less than the specified * key; if no such entry exists, returns {@code null}. */ final Entry getFloorEntry(Int key) { Entry p = root; while (p != null) { int cmp = compare(key, p.key); if (cmp > 0) { if (p.right != null) p = p.right; else return p; } else if (cmp < 0) { if (p.left != null) { p = p.left; } else { Entry parent = p.parent; Entry ch = p; while (parent != null && ch == parent.left) { ch = parent; parent = parent.parent; } return parent; } } else return p; } return null; } final Entry getHigherEntry(Int key) { Entry p = root; while (p != null) { int cmp = compare(key, p.key); if (cmp < 0) { if (p.left != null) p = p.left; else return p; } else { if (p.right != null) { p = p.right; } else { Entry parent = p.parent; Entry ch = p; while (parent != null && ch == parent.right) { ch = parent; parent = parent.parent; } return parent; } } } return null; } final Entry getLowerEntry(Int key) { Entry p = root; while (p != null) { int cmp = compare(key, p.key); if (cmp > 0) { if (p.right != null) p = p.right; else return p; } else { if (p.left != null) { p = p.left; } else { Entry parent = p.parent; Entry ch = p; while (parent != null && ch == parent.left) { ch = parent; parent = parent.parent; } return parent; } } } return null; } public A put(Int key, A value) { Entry t = root; if (t == null) { compare(key, key); // type (and possibly null) check root = new Entry<>(key, value, null); //size = 1; modCount++; return null; } int cmp; Entry parent; // split comparator and comparable paths Comparator cpr = comparator; if (cpr != null) { do { parent = t; cmp = cpr.compare(key, t.key); if (cmp < 0) t = t.left; else if (cmp > 0) t = t.right; else return t.setValue(value); } while (t != null); } else { if (key == null) throw new NullPointerException(); @SuppressWarnings("unchecked") Comparable k = (Comparable) key; do { parent = t; cmp = k.compareTo(t.key); if (cmp < 0) t = t.left; else if (cmp > 0) t = t.right; else return t.setValue(value); } while (t != null); } Entry e = new Entry<>(key, value, parent); if (cmp < 0) parent.left = e; else parent.right = e; fixAfterInsertion(e); size++; modCount++; return null; } public A remove(Object key) { Entry p = getEntry(key); if (p == null) return null; A oldValue = p.value; deleteEntry(p); return oldValue; } public void clear() { modCount++; //size = 0; root = null; } public Map.Entry firstEntry() { return exportEntry(getFirstEntry()); } public Map.Entry lastEntry() { return exportEntry(getLastEntry()); } public Map.Entry lowerEntry(Int key) { return exportEntry(getLowerEntry(key)); } public Int lowerKey(Int key) { return keyOrNull(getLowerEntry(key)); } public Map.Entry floorEntry(Int key) { return exportEntry(getFloorEntry(key)); } public Int floorKey(Int key) { return keyOrNull(getFloorEntry(key)); } public Map.Entry ceilingEntry(Int key) { return exportEntry(getCeilingEntry(key)); } /** * @throws ClassCastException {@inheritDoc} * @throws NullPointerException if the specified key is null * and this map uses natural ordering, or its comparator * does not permit null keys * @since 1.6 */ public Int ceilingKey(Int key) { return keyOrNull(getCeilingEntry(key)); } public Map.Entry higherEntry(Int key) { return exportEntry(getHigherEntry(key)); } public Int higherKey(Int key) { return keyOrNull(getHigherEntry(key)); } // Red-black mechanics private static final boolean RED = false; private static final boolean BLACK = true; /** * Node in the Tree. Doubles as a means to pass key-value pairs back to * user (see Map.Entry). */ static final class Entry { int size = 1; // entry count of subtree //Int key; A value; Entry left; Entry right; Entry parent; boolean color = BLACK; /** * Make a new cell with given value and parent, and with * {@code null} child links, size 1, and BLACK color. */ Entry(A value, Entry parent) { this.key = key; this.value = value; this.parent = parent; } public A getValue() { return value; } public A setValue(A value) { A oldValue = this.value; this.value = value; return oldValue; } } final Entry getFirstEntry() { Entry p = root; if (p != null) while (p.left != null) p = p.left; return p; } final Entry getLastEntry() { Entry p = root; if (p != null) while (p.right != null) p = p.right; return p; } static LogNArray.Entry successor(Entry t) { if (t == null) return null; else if (t.right != null) { Entry p = t.right; while (p.left != null) p = p.left; return p; } else { Entry p = t.parent; Entry ch = t; while (p != null && ch == p.right) { ch = p; p = p.parent; } return p; } } static Entry predecessor(Entry t) { if (t == null) return null; else if (t.left != null) { Entry p = t.left; while (p.right != null) p = p.right; return p; } else { Entry p = t.parent; Entry ch = t; while (p != null && ch == p.left) { ch = p; p = p.parent; } return p; } } /** * Balancing operations. * * Implementations of rebalancings during insertion and deletion are * slightly different than the CLR version. Rather than using dummy * nilnodes, we use a set of accessors that deal properly with null. They * are used to avoid messiness surrounding nullness checks in the main * algorithms. */ private static boolean colorOf(Entry p) { return (p == null ? BLACK : p.color); } private static Entry parentOf(Entry p) { return (p == null ? null: p.parent); } private static void setColor(Entry p, boolean c) { if (p != null) p.color = c; } private static Entry leftOf(Entry p) { return (p == null) ? null: p.left; } private static Entry rightOf(Entry p) { return (p == null) ? null: p.right; } /** From CLR */ private void rotateLeft(Entry p) { if (p != null) { Entry r = p.right; p.right = r.left; if (r.left != null) r.left.parent = p; r.parent = p.parent; if (p.parent == null) root = r; else if (p.parent.left == p) p.parent.left = r; else p.parent.right = r; r.left = p; p.parent = r; } } /** From CLR */ private void rotateRight(Entry p) { if (p != null) { Entry l = p.left; p.left = l.right; if (l.right != null) l.right.parent = p; l.parent = p.parent; if (p.parent == null) root = l; else if (p.parent.right == p) p.parent.right = l; else p.parent.left = l; l.right = p; p.parent = l; } } /** From CLR */ private void fixAfterInsertion(Entry x) { x.color = RED; while (x != null && x != root && x.parent.color == RED) { if (parentOf(x) == leftOf(parentOf(parentOf(x)))) { Entry y = rightOf(parentOf(parentOf(x))); if (colorOf(y) == RED) { setColor(parentOf(x), BLACK); setColor(y, BLACK); setColor(parentOf(parentOf(x)), RED); x = parentOf(parentOf(x)); } else { if (x == rightOf(parentOf(x))) { x = parentOf(x); rotateLeft(x); } setColor(parentOf(x), BLACK); setColor(parentOf(parentOf(x)), RED); rotateRight(parentOf(parentOf(x))); } } else { Entry y = leftOf(parentOf(parentOf(x))); if (colorOf(y) == RED) { setColor(parentOf(x), BLACK); setColor(y, BLACK); setColor(parentOf(parentOf(x)), RED); x = parentOf(parentOf(x)); } else { if (x == leftOf(parentOf(x))) { x = parentOf(x); rotateRight(x); } setColor(parentOf(x), BLACK); setColor(parentOf(parentOf(x)), RED); rotateLeft(parentOf(parentOf(x))); } } } root.color = BLACK; } /** * Delete node p, and then rebalance the tree. */ private void deleteEntry(Entry p) { modCount++; size--; // If strictly internal, copy successor's element to p and then make p // point to successor. if (p.left != null && p.right != null) { Entry s = successor(p); p.key = s.key; p.value = s.value; p = s; } // p has 2 children // Start fixup at replacement node, if it exists. Entry replacement = (p.left != null ? p.left : p.right); if (replacement != null) { // Link replacement to parent replacement.parent = p.parent; if (p.parent == null) root = replacement; else if (p == p.parent.left) p.parent.left = replacement; else p.parent.right = replacement; // Null out links so they are OK to use by fixAfterDeletion. p.left = p.right = p.parent = null; // Fix replacement if (p.color == BLACK) fixAfterDeletion(replacement); } else if (p.parent == null) { // return if we are the only node. root = null; } else { // No children. Use self as phantom replacement and unlink. if (p.color == BLACK) fixAfterDeletion(p); if (p.parent != null) { if (p == p.parent.left) p.parent.left = null; else if (p == p.parent.right) p.parent.right = null; p.parent = null; } } } /** From CLR */ private void fixAfterDeletion(Entry x) { while (x != root && colorOf(x) == BLACK) { if (x == leftOf(parentOf(x))) { Entry sib = rightOf(parentOf(x)); if (colorOf(sib) == RED) { setColor(sib, BLACK); setColor(parentOf(x), RED); rotateLeft(parentOf(x)); sib = rightOf(parentOf(x)); } if (colorOf(leftOf(sib)) == BLACK && colorOf(rightOf(sib)) == BLACK) { setColor(sib, RED); x = parentOf(x); } else { if (colorOf(rightOf(sib)) == BLACK) { setColor(leftOf(sib), BLACK); setColor(sib, RED); rotateRight(sib); sib = rightOf(parentOf(x)); } setColor(sib, colorOf(parentOf(x))); setColor(parentOf(x), BLACK); setColor(rightOf(sib), BLACK); rotateLeft(parentOf(x)); x = root; } } else { // symmetric Entry sib = leftOf(parentOf(x)); if (colorOf(sib) == RED) { setColor(sib, BLACK); setColor(parentOf(x), RED); rotateRight(parentOf(x)); sib = leftOf(parentOf(x)); } if (colorOf(rightOf(sib)) == BLACK && colorOf(leftOf(sib)) == BLACK) { setColor(sib, RED); x = parentOf(x); } else { if (colorOf(leftOf(sib)) == BLACK) { setColor(rightOf(sib), BLACK); setColor(sib, RED); rotateLeft(sib); sib = leftOf(parentOf(x)); } setColor(sib, colorOf(parentOf(x))); setColor(parentOf(x), BLACK); setColor(leftOf(sib), BLACK); rotateRight(parentOf(x)); x = root; } } } setColor(x, BLACK); } /** * Finds the level down to which to assign all nodes BLACK. This is the * last `full' level of the complete binary tree produced by buildTree. * The remaining nodes are colored RED. (This makes a `nice' set of * color assignments wrt future insertions.) This level number is * computed by finding the number of splits needed to reach the zeroeth * node. * * @param size the (non-negative) number of keys in the tree to be built */ private static int computeRedLevel(int size) { return 31 - Integer.numberOfLeadingZeros(size + 1); } }