Mercurial > projects > doodle
view 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 source
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); }