Mercurial > projects > doodle
diff doodle/containers/tree_set.d @ 40:1f97022e5c6d
Checkpoint. Development continues...
author | daveb |
---|---|
date | Mon, 12 Apr 2010 14:01:54 +0930 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doodle/containers/tree_set.d Mon Apr 12 14:01:54 2010 +0930 @@ -0,0 +1,772 @@ +module delve.util.set; + +class Set(T) { + this() { + } + + bool isEmpty() { + return _root is null; + } + + size_t size() { + return 0; // FIXME + } + + // Error if already present + void add(T t) { + } + + // Error if not present + void remove(T t) { + } + + bool contains(T t) { + return false; // FIXME + } + + void clear() { + } + + int opApply(int delegate (inout T) dg) { + return 0; // FIXME + } + + /* + void erase(Iterator iter) { + } + + class Iterator { + T element(); + + void goNext() { + } + + void goPrevious() { + } + + bool nextValid() { + } + + bool previousValid() { + } + + Cell _cell; + } + */ + + private { + void _add(T t) { + if (_root is null) { + _root = new Cell(t); + } + else { + } + + ++_size; + } + + class Cell { + static bool RED = false; + static bool BLACK = true; + + /** + * The node color (RED, BLACK) + **/ + + bool color_; + + /** + * Pointer to left child + **/ + + Cell left_; + + /** + * Pointer to right child + **/ + + Cell right_; + + T _element; + + /** + * Pointer to parent (null if root) + **/ + + private Cell parent_; + + /** + * Make a new Cell with given element, null links, and BLACK color. + * Normally only called to establish a new root. + **/ + + public this (T element) { + _element = element; + left_ = null; + right_ = null; + parent_ = null; + color_ = BLACK; + } + + /** + * Return a new Cell with same element and color as self, + * but with null links. (Since it is never OK to have + * multiple identical links in a RB tree.) + **/ + + protected Cell duplicate() { + Cell t = new Cell(_element); + t.color_ = color_; + return t; + } + + + /** + * Return left child (or null) + **/ + + public final Cell left() { + return left_; + } + + /** + * Return right child (or null) + **/ + + public final Cell right() { + return right_; + } + + /** + * Return parent (or null) + **/ + public final Cell parent() { + return parent_; + } + + + /** + * See_Also: tango.util.collection.model.View.View.checkImplementation. + **/ + public void checkImplementation() { + + // It's too hard to check the property that every simple + // path from node to leaf has same number of black nodes. + // So restrict to the following + + assert(parent_ is null || this is parent_.left_ || this is parent_.right_); + assert(left_ is null || this is left_.parent_); + assert(right_ is null || this is right_.parent_); + assert(color_ is BLACK || (colorOf(left_) is BLACK) && (colorOf(right_) is BLACK)); + + if (left_ !is null) + left_.checkImplementation(); + if (right_ !is null) + right_.checkImplementation(); + } + + /** + * Return the minimum element of the current (sub)tree + **/ + + public final Cell leftmost() { + auto p = this; + for ( ; p.left_ !is null; p = p.left_) { + } + return p; + } + + /** + * Return the maximum element of the current (sub)tree + **/ + public final Cell rightmost() { + auto p = this; + for ( ; p.right_ !is null; p = p.right_) { + } + return p; + } + + /** + * Return the root (parentless node) of the tree + **/ + public final Cell root() { + auto p = this; + for ( ; p.parent_ !is null; p = p.parent_) { + } + return p; + } + + /** + * Return true if node is a root (i.e., has a null parent) + **/ + + public final bool isRoot() { + return parent_ is null; + } + + + /** + * Return the inorder successor, or null if no such + **/ + + public final Cell successor() { + if (right_ !is null) + return right_.leftmost(); + else { + auto p = parent_; + auto ch = this; + while (p !is null && ch is p.right_) { + ch = p; + p = p.parent_; + } + return p; + } + } + + /** + * Return the inorder predecessor, or null if no such + **/ + + public final Cell predecessor() { + if (left_ !is null) + return left_.rightmost(); + else + { + auto p = parent_; + auto ch = this; + while (p !is null && ch is p.left_) + { + ch = p; + p = p.parent_; + } + return p; + } + } + + /** + * Return the number of nodes in the subtree + **/ + public final int size() { + int c = 1; + if (left_ !is null) + c += left_.size(); + if (right_ !is null) + c += right_.size(); + return c; + } + + + /** + * Return node of current subtree containing element as element(), + * if it exists, else null. + * Uses Comparator cmp to find and to check equality. + **/ + + /+ + public Cell find(T element, Comparator!(T) cmp) { + auto t = this; + for (;;) { + int diff = cmp.compare(element, t.element()); + if (diff is 0) + return t; + else + if (diff < 0) + t = t.left_; + else + t = t.right_; + if (t is null) + break; + } + return null; + } + + + /** + * Return number of nodes of current subtree containing element. + * Uses Comparator cmp to find and to check equality. + **/ + public int count(T element, Comparator!(T) cmp) { + int c = 0; + auto t = this; + while (t !is null) { + int diff = cmp.compare(element, t.element()); + if (diff is 0) { + ++c; + if (t.left_ is null) + t = t.right_; + else + if (t.right_ is null) + t = t.left_; + else { + c += t.right_.count(element, cmp); + t = t.left_; + } + } + else + if (diff < 0) + t = t.left_; + else + t = t.right_; + } + return c; + } + +/ + + + + + /** + * Return a new subtree containing each element of current subtree + **/ + + public final Cell copyTree() { + auto t = cast(Cell)(duplicate()); + + if (left_ !is null) { + t.left_ = left_.copyTree(); + t.left_.parent_ = t; + } + if (right_ !is null) { + t.right_ = right_.copyTree(); + t.right_.parent_ = t; + } + return t; + } + + + /** + * There's no generic element insertion. Instead find the + * place you want to add a node and then invoke insertLeft + * or insertRight. + * <P> + * Insert Cell as the left child of current node, and then + * rebalance the tree it is in. + * @param Cell the Cell to add + * @param root, the root of the current tree + * Returns: the new root of the current tree. (Rebalancing + * can change the root!) + **/ + + + public final Cell insertLeft(Cell Cell, Cell root) { + left_ = Cell; + Cell.parent_ = this; + return Cell.fixAfterInsertion(root); + } + + /** + * Insert Cell as the right child of current node, and then + * rebalance the tree it is in. + * @param Cell the Cell to add + * @param root, the root of the current tree + * Returns: the new root of the current tree. (Rebalancing + * can change the root!) + **/ + + public final Cell insertRight(Cell Cell, Cell root) { + right_ = Cell; + Cell.parent_ = this; + return Cell.fixAfterInsertion(root); + } + + + /** + * Delete the current node, and then rebalance the tree it is in + * @param root the root of the current tree + * Returns: the new root of the current tree. (Rebalancing + * can change the root!) + **/ + + + public final Cell remove (Cell root) { + + // handle case where we are only node + if (left_ is null && right_ is null && parent_ is null) + return null; + + // if strictly internal, swap places with a successor + if (left_ !is null && right_ !is null) { + auto s = successor(); + // To work nicely with arbitrary subclasses of Cell, we don't want to + // just copy successor's fields. since we don't know what + // they are. Instead we swap positions _in the tree. + root = swapPosition(this, s, root); + } + + // Start fixup at replacement node (normally a child). + // But if no children, fake it by using self + + if (left_ is null && right_ is null) { + + if (color_ is BLACK) + root = this.fixAfterDeletion(root); + + // Unlink (Couldn't before since fixAfterDeletion needs parent ptr) + + if (parent_ !is null) { + if (this is parent_.left_) + parent_.left_ = null; + else + if (this is parent_.right_) + parent_.right_ = null; + parent_ = null; + } + + } + else { + auto replacement = left_; + if (replacement is null) + replacement = right_; + + // link replacement to parent + replacement.parent_ = parent_; + + if (parent_ is null) + root = replacement; + else + if (this is parent_.left_) + parent_.left_ = replacement; + else + parent_.right_ = replacement; + + left_ = null; + right_ = null; + parent_ = null; + + // fix replacement + if (color_ is BLACK) + root = replacement.fixAfterDeletion(root); + + } + + return root; + } + + /** + * Swap the linkages of two nodes in a tree. + * Return new root, in case it changed. + **/ + + static final Cell swapPosition(Cell x, Cell y, Cell root) { + + /* Too messy. TODO: find sequence of assigments that are always OK */ + + auto px = x.parent_; + bool xpl = px !is null && x is px.left_; + auto lx = x.left_; + auto rx = x.right_; + + auto py = y.parent_; + bool ypl = py !is null && y is py.left_; + auto ly = y.left_; + auto ry = y.right_; + + if (x is py) { + y.parent_ = px; + if (px !is null) + if (xpl) + px.left_ = y; + else + px.right_ = y; + x.parent_ = y; + if (ypl) { + y.left_ = x; + y.right_ = rx; + if (rx !is null) + rx.parent_ = y; + } + else { + y.right_ = x; + y.left_ = lx; + if (lx !is null) + lx.parent_ = y; + } + x.left_ = ly; + if (ly !is null) + ly.parent_ = x; + x.right_ = ry; + if (ry !is null) + ry.parent_ = x; + } + else + if (y is px) { + x.parent_ = py; + if (py !is null) + if (ypl) + py.left_ = x; + else + py.right_ = x; + y.parent_ = x; + if (xpl) { + x.left_ = y; + x.right_ = ry; + if (ry !is null) + ry.parent_ = x; + } + else { + x.right_ = y; + x.left_ = ly; + if (ly !is null) + ly.parent_ = x; + } + y.left_ = lx; + if (lx !is null) + lx.parent_ = y; + y.right_ = rx; + if (rx !is null) + rx.parent_ = y; + } + else { + x.parent_ = py; + if (py !is null) + if (ypl) + py.left_ = x; + else + py.right_ = x; + x.left_ = ly; + if (ly !is null) + ly.parent_ = x; + x.right_ = ry; + if (ry !is null) + ry.parent_ = x; + + y.parent_ = px; + if (px !is null) + if (xpl) + px.left_ = y; + else + px.right_ = y; + y.left_ = lx; + if (lx !is null) + lx.parent_ = y; + y.right_ = rx; + if (rx !is null) + rx.parent_ = y; + } + + bool c = x.color_; + x.color_ = y.color_; + y.color_ = c; + + if (root is x) { + root = y; + } + else { + if (root is y) + root = x; + } + return root; + } + + + + /** + * Return color of node p, or BLACK if p is null + * (In the CLR version, they use + * a special dummy `nil' node for such purposes, but that doesn't + * work well here, since it could lead to creating one such special + * node per real node.) + * + **/ + + static final bool colorOf(Cell p) { + return (p is null) ? BLACK : p.color_; + } + + /** + * return parent of node p, or null if p is null + **/ + static final Cell parentOf(Cell p) { + return (p is null) ? null : p.parent_; + } + + /** + * Set the color of node p, or do nothing if p is null + **/ + + static final void setColor(Cell p, bool c) { + if (p !is null) + p.color_ = c; + } + + /** + * return left child of node p, or null if p is null + **/ + + static final Cell leftOf(Cell p) { + return (p is null) ? null : p.left_; + } + + /** + * return right child of node p, or null if p is null + **/ + + static final Cell rightOf(Cell p) { + return (p is null) ? null : p.right_; + } + + + /** From CLR **/ + protected final Cell rotateLeft(Cell root) { + auto r = right_; + right_ = r.left_; + if (r.left_ !is null) + r.left_.parent_ = this; + r.parent_ = parent_; + if (parent_ is null) + root = r; + else { + if (parent_.left_ is this) + parent_.left_ = r; + else + parent_.right_ = r; + } + r.left_ = this; + parent_ = r; + return root; + } + + /** From CLR **/ + protected final Cell rotateRight(Cell root) { + auto l = left_; + left_ = l.right_; + if (l.right_ !is null) + l.right_.parent_ = this; + l.parent_ = parent_; + if (parent_ is null) { + root = l; + } + else { + if (parent_.right_ is this) + parent_.right_ = l; + else + parent_.left_ = l; + } + l.right_ = this; + parent_ = l; + return root; + } + + + /** From CLR **/ + protected final Cell fixAfterInsertion(Cell root) { + color_ = RED; + auto x = this; + + while (x !is null && x !is root && x.parent_.color_ is RED) { + if (parentOf(x) is leftOf(parentOf(parentOf(x)))) { + auto y = rightOf(parentOf(parentOf(x))); + if (colorOf(y) is RED) { + setColor(parentOf(x), BLACK); + setColor(y, BLACK); + setColor(parentOf(parentOf(x)), RED); + x = parentOf(parentOf(x)); + } + else { + if (x is rightOf(parentOf(x))) { + x = parentOf(x); + root = x.rotateLeft(root); + } + setColor(parentOf(x), BLACK); + setColor(parentOf(parentOf(x)), RED); + if (parentOf(parentOf(x)) !is null) { + root = parentOf(parentOf(x)).rotateRight(root); + } + } + } + else { + auto y = leftOf(parentOf(parentOf(x))); + if (colorOf(y) is RED) { + setColor(parentOf(x), BLACK); + setColor(y, BLACK); + setColor(parentOf(parentOf(x)), RED); + x = parentOf(parentOf(x)); + } + else { + if (x is leftOf(parentOf(x))) { + x = parentOf(x); + root = x.rotateRight(root); + } + setColor(parentOf(x), BLACK); + setColor(parentOf(parentOf(x)), RED); + if (parentOf(parentOf(x)) !is null) + root = parentOf(parentOf(x)).rotateLeft(root); + } + } + } + root.color_ = BLACK; + return root; + } + + + + /** From CLR **/ + protected final Cell fixAfterDeletion(Cell root) { + auto x = this; + while (x !is root && colorOf(x) is BLACK) { + if (x is leftOf(parentOf(x))) { + auto sib = rightOf(parentOf(x)); + if (colorOf(sib) is RED) { + setColor(sib, BLACK); + setColor(parentOf(x), RED); + root = parentOf(x).rotateLeft(root); + sib = rightOf(parentOf(x)); + } + + if (colorOf(leftOf(sib)) is BLACK && colorOf(rightOf(sib)) is BLACK) { + setColor(sib, RED); + x = parentOf(x); + } + else { + if (colorOf(rightOf(sib)) is BLACK) { + setColor(leftOf(sib), BLACK); + setColor(sib, RED); + root = sib.rotateRight(root); + sib = rightOf(parentOf(x)); + } + setColor(sib, colorOf(parentOf(x))); + setColor(parentOf(x), BLACK); + setColor(rightOf(sib), BLACK); + root = parentOf(x).rotateLeft(root); + x = root; + } + } + else { + auto sib = leftOf(parentOf(x)); + if (colorOf(sib) is RED) { + setColor(sib, BLACK); + setColor(parentOf(x), RED); + root = parentOf(x).rotateRight(root); + sib = leftOf(parentOf(x)); + } + if (colorOf(rightOf(sib)) is BLACK && colorOf(leftOf(sib)) is BLACK) { + setColor(sib, RED); + x = parentOf(x); + } + else { + if (colorOf(leftOf(sib)) is BLACK) { + setColor(rightOf(sib), BLACK); + setColor(sib, RED); + root = sib.rotateLeft(root); + sib = leftOf(parentOf(x)); + } + setColor(sib, colorOf(parentOf(x))); + setColor(parentOf(x), BLACK); + setColor(leftOf(sib), BLACK); + root = parentOf(x).rotateRight(root); + x = root; + } + } + } + setColor(x, BLACK); + return root; + } + } + + Cell _root; + size_t _size; + } +} +unittest { + auto s = new Set!(int); +}