Libraryless. Click here for Pure Java version (482L/4K).
// see: https://en.wikipedia.org/wiki/Order_statistic_tree sclass LogNArray<A> extends RandomAccessAbstractList<A> { private transient Entry<A> 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<A> e = getFirstEntry(); e != null; e = successor(e)) if (eq(value, e.value)) true; false; } public A get(int idx) { Entry<A> p = getEntry(idx); return p == null ? null : p.value; } int subTreeSize(Entry<A> e) { ret e == null ? 0 : e.size; } final Entry<A> getEntry(int idx) { if (idx < 0 || idx >= size()) throw new IndexOutOfBoundsException(idx + " / " + size()); Entry<A> p = root; while true { int sizeLeft = subTreeSize(p.left); if (idx < sizeLeft) continue with p = p.left; idx -= sizeLeft; if (idx == 0) ret p; idx--; p = p.right; } } /*public A put(Int key, A value) { Entry<A> 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<A> parent; // split comparator and comparable paths Comparator<? super Int> 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<? super Int> k = (Comparable<? super Int>) 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<A> 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(int idx) { Entry<A> p = getEntry(key); if (p == null) return null; A oldValue = p.value; deleteEntry(p); return oldValue; }*/ public void clear() { modCount++; //size = 0; root = null; } // 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<A> { int size = 1; // entry count of subtree //Int key; A value; Entry<A> left; Entry<A> right; Entry<A> 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<A> parent) { this.value = value; this.parent = parent; } } final Entry<A> getFirstEntry() { Entry<A> p = root; if (p != null) while (p.left != null) p = p.left; return p; } final Entry<A> getLastEntry() { Entry<A> p = root; if (p != null) while (p.right != null) p = p.right; return p; } static <Int,A> LogNArray.Entry<A> successor(Entry<A> t) { if (t == null) return null; else if (t.right != null) { Entry<A> p = t.right; while (p.left != null) p = p.left; return p; } else { Entry<A> p = t.parent; Entry<A> ch = t; while (p != null && ch == p.right) { ch = p; p = p.parent; } return p; } } static <Int,A> Entry<A> predecessor(Entry<A> t) { if (t == null) return null; else if (t.left != null) { Entry<A> p = t.left; while (p.right != null) p = p.right; return p; } else { Entry<A> p = t.parent; Entry<A> 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 <Int,A> boolean colorOf(Entry<A> p) { return (p == null ? BLACK : p.color); } private static <Int,A> Entry<A> parentOf(Entry<A> p) { return (p == null ? null: p.parent); } private static <Int,A> void setColor(Entry<A> p, boolean c) { if (p != null) p.color = c; } private static <Int,A> Entry<A> leftOf(Entry<A> p) { return (p == null) ? null: p.left; } private static <Int,A> Entry<A> rightOf(Entry<A> p) { return (p == null) ? null: p.right; } /** From CLR */ private void rotateLeft(Entry<A> p) { if (p != null) { Entry<A> 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<A> p) { if (p != null) { Entry<A> 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<A> x) { x.color = RED; while (x != null && x != root && x.parent.color == RED) { if (parentOf(x) == leftOf(parentOf(parentOf(x)))) { Entry<A> 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<A> 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<A> 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<A> s = successor(p); p.value = s.value; p = s; } // p has 2 children // Start fixup at replacement node, if it exists. Entry<A> 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<A> x) { while (x != root && colorOf(x) == BLACK) { if (x == leftOf(parentOf(x))) { Entry<A> 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<A> 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); } }
Began life as a copy of #1024411
download show line numbers debug dex old transpilations
Travelled to 6 computer(s): bhatertpkbcr, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tvejysmllsmz, vouqrxazstgt
No comments. add comment
Snippet ID: | #1024412 |
Snippet name: | LogNArray v2 [based on TreeMap, dev.] |
Eternal ID of this version: | #1024412/12 |
Text MD5: | e218fba96a516a2cc9c23442a664817e |
Transpilation MD5: | ba1ee5307ba902cc8076a7b714b727b9 |
Author: | stefan |
Category: | javax |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2019-08-11 11:38:26 |
Source code size: | 12931 bytes / 438 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 279 / 390 |
Version history: | 11 change(s) |
Referenced in: | #1024413 - LogNArray v3 [works at least with add, remove, get, set] |