added rotate() and adjust() to RedBlackTree
This commit is contained in:
parent
88e2e477b9
commit
ecdb510e4b
@ -34,29 +34,76 @@
|
|||||||
QSE_BEGIN_NAMESPACE(QSE)
|
QSE_BEGIN_NAMESPACE(QSE)
|
||||||
/////////////////////////////////
|
/////////////////////////////////
|
||||||
|
|
||||||
template <typename T>
|
template <typename T, typename COMPARATOR> class RedBlackTree;
|
||||||
|
|
||||||
|
template <typename T, typename COMPARATOR>
|
||||||
class RedBlackTreeNode
|
class RedBlackTreeNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
friend class RedBlackTree<T>;
|
friend class RedBlackTree<T,COMPARATOR>;
|
||||||
typedef RedBlackTreeNode<T> SelfType;
|
typedef RedBlackTreeNode<T,COMPARATOR> SelfType;
|
||||||
|
|
||||||
enum
|
enum Color
|
||||||
{
|
{
|
||||||
RED,
|
RED,
|
||||||
BLACK
|
BLACK
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum Child
|
||||||
|
{
|
||||||
|
LEFT,
|
||||||
|
RIGHT
|
||||||
|
};
|
||||||
|
|
||||||
T value; // you can use this variable or accessor functions below
|
T value; // you can use this variable or accessor functions below
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
Color color;
|
||||||
SelfType* parent;
|
SelfType* parent;
|
||||||
SelfType* child[2]; // left and right
|
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:
|
public:
|
||||||
T& getValue () { return this->value; }
|
T& getValue () { return this->value; }
|
||||||
const T& getValue () const { return this->value; }
|
const T& getValue () const { return this->value; }
|
||||||
void setValue (const T& v) { this->value = v; }
|
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<typename T>
|
template<typename T>
|
||||||
@ -74,14 +121,18 @@ class RedBlackTree: public Mmged
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef RedBlackTree<T,COMPARATOR> SelfType;
|
typedef RedBlackTree<T,COMPARATOR> SelfType;
|
||||||
|
typedef RedBlackTreeNode<T,COMPARATOR> Node;
|
||||||
|
|
||||||
typedef RedBlackTreeHasher<T> DefaultHasher;
|
|
||||||
typedef RedBlackTreeComparator<T> DefaultComparator;
|
typedef RedBlackTreeComparator<T> DefaultComparator;
|
||||||
|
|
||||||
RedBlackTree
|
RedBlackTree (Mmgr* mmgr = QSE_NULL, qse_size_t mpb_size = 0): Mmged(mmgr), mp (mmgr, QSE_SIZEOF(Node), mpb_size), node_count (0)
|
||||||
Mmgr* mmgr = QSE_NULL,
|
|
||||||
qse_size_t mpb_size = 0): Mmged(mmgr)
|
|
||||||
{
|
{
|
||||||
|
// 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)
|
RedBlackTree (const RedBlackTree& rbt)
|
||||||
@ -118,12 +169,261 @@ public:
|
|||||||
return this->node_count <= 0;
|
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:
|
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)
|
Node* inject (const T& datum, int mode, bool* injected = 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;
|
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)
|
Node* insert (const T& datum)
|
||||||
{
|
{
|
||||||
@ -149,13 +449,21 @@ public:
|
|||||||
}
|
}
|
||||||
#endif
|
#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:
|
protected:
|
||||||
Mpool mp;
|
Mpool mp;
|
||||||
COMPARATOR comparator;
|
COMPARATOR comparator;
|
||||||
|
|
||||||
Node xnil; // internal node to present nil
|
|
||||||
Node* root; // root node.
|
|
||||||
qse_size_t node_count;
|
qse_size_t node_count;
|
||||||
|
Node* nil; // internal node to present nil
|
||||||
|
Node* root; // root node.
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -350,7 +350,7 @@ static void rotate (rbt_t* rbt, pair_t* pivot, int leftwise)
|
|||||||
parent = pivot->parent;
|
parent = pivot->parent;
|
||||||
/* y for leftwise rotation, x for rightwise rotation */
|
/* y for leftwise rotation, x for rightwise rotation */
|
||||||
z = pivot->child[cid1];
|
z = pivot->child[cid1];
|
||||||
/* c1 for leftwise rotation, c1 for rightwise rotation */
|
/* c1 for leftwise rotation, c2 for rightwise rotation */
|
||||||
c = z->child[cid2];
|
c = z->child[cid2];
|
||||||
|
|
||||||
z->parent = parent;
|
z->parent = parent;
|
||||||
|
Loading…
Reference in New Issue
Block a user