From ecdb510e4b08b09eb2f92db41689d2015c6ac448 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Sat, 28 Feb 2015 16:21:01 +0000 Subject: [PATCH] added rotate() and adjust() to RedBlackTree --- qse/include/qse/cmn/RedBlackTree.hpp | 330 ++++++++++++++++++++++++++- qse/lib/cmn/rbt.c | 8 +- 2 files changed, 323 insertions(+), 15 deletions(-) diff --git a/qse/include/qse/cmn/RedBlackTree.hpp b/qse/include/qse/cmn/RedBlackTree.hpp index 0554bd97..0dc8ac4c 100644 --- a/qse/include/qse/cmn/RedBlackTree.hpp +++ b/qse/include/qse/cmn/RedBlackTree.hpp @@ -34,29 +34,76 @@ QSE_BEGIN_NAMESPACE(QSE) ///////////////////////////////// -template +template class RedBlackTree; + +template class RedBlackTreeNode { public: - friend class RedBlackTree; - typedef RedBlackTreeNode SelfType; + friend class RedBlackTree; + typedef RedBlackTreeNode SelfType; - enum + enum Color { RED, BLACK }; + enum Child + { + LEFT, + RIGHT + }; + T value; // you can use this variable or accessor functions below protected: + Color color; SelfType* parent; SelfType* child[2]; // left and right + RedBlackTreeNode() + { + // no initialization. make sure to initialize member variables later + } + + RedBlackTreeNode(const T& value, Color color, SelfType* parent, SelfType* left, SelfType* right): + value (value), color (color), parent (parent) + { + this->child[LEFT] = left; + this->child[RIGHT] = right; + } + public: T& getValue () { return this->value; } const T& getValue () const { return this->value; } void setValue (const T& v) { this->value = v; } + + bool isBlack () const { return this->color == BLACK; } + bool isRed () const { return this->color == RED; } + void setBlack () { this->color = BLACK; } + void setRed () { this->color = RED; } + + SelfType* getParent () { return this->parent; } + const SelfType* getParent () const { return this->parent; } + + SelfType* getLeft () { return this->child[LEFT]; } + const SelfType* getLeft () const { return this->child[LEFT]; } + + SelfType* getRight () { return this->child[RIGHT]; } + const SelfType* getRight () const { return this->child[RIGHT]; } + + void setParent (SelfType* node) { this->parent = node; } + void setLeft (SelfType* node) { this->child[LEFT] = node; } + void setRight (SelfType* node) { this->child[RIGHT] = node; } + + void setAll (Color color, SelfType* parent, SelfType* left, SelfType* right) + { + this->color = color; + this->parent = parent; + this->child[LEFT] = left; + this->child[RIGHT] = right; + } }; template @@ -74,14 +121,18 @@ class RedBlackTree: public Mmged { public: typedef RedBlackTree SelfType; + typedef RedBlackTreeNode Node; - typedef RedBlackTreeHasher DefaultHasher; typedef RedBlackTreeComparator DefaultComparator; - RedBlackTree - Mmgr* mmgr = QSE_NULL, - qse_size_t mpb_size = 0): Mmged(mmgr) + RedBlackTree (Mmgr* mmgr = QSE_NULL, qse_size_t mpb_size = 0): Mmged(mmgr), mp (mmgr, QSE_SIZEOF(Node), mpb_size), node_count (0) { + // initialize nil + this->nil = new(&this->mp) Node(); + this->nil->setAll (Node::BLACK, this->nil, this->nil, this->nil); + + // set root to nil + this->root = this->nil; } RedBlackTree (const RedBlackTree& rbt) @@ -118,11 +169,260 @@ public: return this->node_count <= 0; } + bool isNil (Node* node) const + { + return node == this->nil; + } + + bool notNil (Node* node) const + { + return node != this->nil; + } + + Node* getRoot () + { + return this->root; + } + + const Node* getRoot () const + { + return this->root; + } + +protected: + Node* find_node (const T& datum) const + { + Node* node = this->root; + + // normal binary tree search + while (notNil (node)) + { + int n = this->comparator (datum, node->value); + if (n == 0) return node; + + if (n > 0) node = node->getRight(); + else /* if (n < 0) */ node = node->getLeft(); + } + + return QSE_NULL; + } + + void rotate (Node* pivot, bool leftwise) + { + /* + * == leftwise rotation + * move the pivot pair down to the poistion of the pivot's original + * left child(x). move the pivot's right child(y) to the pivot's original + * position. as 'c1' is between 'y' and 'pivot', move it to the right + * of the new pivot position. + * parent parent + * | | (left or right?) | | + * pivot y + * / \ / \ + * x y =====> pivot c2 + * / \ / \ + * c1 c2 x c1 + * + * == rightwise rotation + * move the pivot pair down to the poistion of the pivot's original + * right child(y). move the pivot's left child(x) to the pivot's original + * position. as 'c2' is between 'x' and 'pivot', move it to the left + * of the new pivot position. + * + * parent parent + * | | (left or right?) | | + * pivot x + * / \ / \ + * x y =====> c1 pivot + * / \ / \ + * c1 c2 c2 y + * + * + * the actual implementation here resolves the pivot's relationship to + * its parent by comparaing pointers as it is not known if the pivot pair + * is the left child or the right child of its parent, + */ + + Node* parent, * z, * c; + + QSE_ASSERT (pivot != QSE_NULL); + + parent = pivot->getParent(); + if (leftwise) + { + // y for leftwise rotation + z = pivot->getRight(); + // c1 for leftwise rotation + c = z->getLeft(); + } + else + { + // x for rightwise rotation + z = pivot->getLeft(); + // c2 for rightwise rotation + c = z->getRight(); + } + + z->setParent (parent); + if (notNil (parent)) + { + if (parent->getLeft() == pivot) + { + parent->setLeft (z); + } + else + { + QSE_ASSERT (parent->getRight() == pivot); + parent->setRight (z); + } + } + else + { + QSE_ASSERT (this->root == pivot); + this->root = z; + } + + if (leftwise) + { + z->setLeft (pivot); + pivot->setRight (c); + } + else + { + z->setRight (pivot); + pivot->setLeft (c); + } + + if (notNil(pivot)) pivot->setParent (z); + if (notNil(c)) c->setParent (pivot); + } + + void adjust (Node* node) + { + while (node != this->root) + { + Node* tmp, * tmp2, * x_par, * x_par_par; + bool leftwise; + + x_par = node->getParent (); + if (x_par->isBlack()) break; + + QSE_ASSERT (notNil (x_par->parent)); + + x_par_par = x_par->getParent (); + if (x_par == x_par_par->getLeft ()) + { + tmp = x_par_par->getRight (); + tmp2 = x_par->getRight (); + leftwise = true; + } + else + { + tmp = x_par_par->getLeft (); + tmp2 = x_par->getLeft (); + leftwise = false; + } + + if (tmp->isRed ()) + { + x_par->setBlack (); + tmp->setBlack (); + x_par_par->setRed (); + node = x_par_par; + } + else + { + if (node == tmp2) + { + node = x_par; + this->rotate (node, leftwise); + x_par = node->getParent(); + x_par_par = x_par->getParent(); + } + + x_par->setBlack(); + x_par_par->setRed(); + this->rotate (x_par_par, !leftwise); + } + } + } + + public: + Node* search (const T& datum) + { + return this->find_node (datum); + } + + const Node* search (const T& datum) const + { + return this->find_node (datum); + } Node* inject (const T& datum, int mode, bool* injected = QSE_NULL) { - return QSE_NULL; + Node* x_cur = this->root; + Node* x_par = this->nil; + + while (notNil (x_cur)) + { + int n = this->comparator (datum, x_cur->value); + if (n == 0) + { + #if 0 + switch (opt) + { + case UPSERT: + case UPDATE: + return change_pair_val (rbt, x_cur, vptr, vlen); + + case ENSERT: + /* return existing pair */ + return x_cur; + + case INSERT: + /* return failure */ + return QSE_NULL; + } + #endif + } + + x_par = x_cur; + + if (n > 0) x_cur = x_cur->getRight (); + else /* if (n < 0) */ x_cur = x_cur->getLeft (); + } + + //if (opt == UPDATE) return QSE_NULL; + + Node* x_new = new(&this->mp) Node (datum, Node::RED, this->nil, this->nil, this->nil); + if (isNil (x_par)) + { + QSE_ASSERT (isNil (this->root)); + this->root = x_new; + } + else + { + int n = this->comparator (datum, x_par->value); + if (n > 0) + { + QSE_ASSERT (isNil (x_par->getRight ())); + x_par->setRight (x_new); + } + else + { + QSE_ASSERT (isNil (x_par->getLeft ())); + x_par->setLeft (x_new); + } + + x_new->setParent (x_par); + this->adjust (x_new); + } + + this->root->setBlack (); + this->node_count++; + + return x_new; } Node* insert (const T& datum) @@ -149,13 +449,21 @@ public: } #endif + void dump (Node* node) + { + printf ("%d %d\n", node->value.getX(), node->value.getY()); + if (notNil(node->getLeft())) dump (node->getLeft()); + if (notNil(node->getRight())) dump (node->getRight()); + } + protected: Mpool mp; COMPARATOR comparator; - Node xnil; // internal node to present nil - Node* root; // root node. qse_size_t node_count; + Node* nil; // internal node to present nil + Node* root; // root node. + }; diff --git a/qse/lib/cmn/rbt.c b/qse/lib/cmn/rbt.c index 75d0cc2f..4170b6a5 100644 --- a/qse/lib/cmn/rbt.c +++ b/qse/lib/cmn/rbt.c @@ -100,7 +100,7 @@ QSE_INLINE pair_t* qse_rbt_allocpair ( KPTR(n) = kcop (rbt, kptr, klen); if (KPTR(n) == QSE_NULL) { - QSE_MMGR_FREE (rbt->mmgr, n); + QSE_MMGR_FREE (rbt->mmgr, n); return QSE_NULL; } } @@ -124,7 +124,7 @@ QSE_INLINE pair_t* qse_rbt_allocpair ( { if (rbt->style->freeer[QSE_RBT_KEY] != QSE_NULL) rbt->style->freeer[QSE_RBT_KEY] (rbt, KPTR(n), KLEN(n)); - QSE_MMGR_FREE (rbt->mmgr, n); + QSE_MMGR_FREE (rbt->mmgr, n); return QSE_NULL; } } @@ -350,7 +350,7 @@ static void rotate (rbt_t* rbt, pair_t* pivot, int leftwise) parent = pivot->parent; /* y for leftwise rotation, x for rightwise rotation */ z = pivot->child[cid1]; - /* c1 for leftwise rotation, c1 for rightwise rotation */ + /* c1 for leftwise rotation, c2 for rightwise rotation */ c = z->child[cid2]; z->parent = parent; @@ -408,7 +408,7 @@ static void adjust (rbt_t* rbt, pair_t* pair) { x_par->color = QSE_RBT_BLACK; tmp->color = QSE_RBT_BLACK; - x_par->parent->color = QSE_RBT_RED; + x_par->parent->color = QSE_RBT_RED; pair = x_par->parent; } else