编程练习——红黑树(RedBlackTree)
在网上搜索了很多红黑树的资源,发现自己看代码的能力还是有些欠缺。很多都看不懂,后来找到一篇英文红黑树文献,终于弄明白了红黑树的删除插入是怎么做的。但是那片文
献好像还有些漏洞,其中有一种删除情况,他并没有考虑到。如果大家想看的话可以搜索下 “red-black trees” ,由 prof. Lyn
Turbak所写。因为时间关系,插入算法只是实现了非CLR算法。删除算法我也不知道叫什么名字(文献里没有讲)。但是删除结果依旧符合红黑树。
建立红黑树节点的时候,考虑到因为经常要和一个节点的父亲节点打交道,所以采用了在节点里添加父亲节点的指针的方法。这样即方便也提高效率。另外也好调试。如果一味采
用递归…估计人会看疯掉的。插入的时候,采用的是先插入删除的时候红色节点,然后在判断是否违反红红条件。违反的话就左旋右旋进行调整。否则就插入成功。删除的时候
先删除节点,这个过程和删除二叉查找树节点一致。删除时要看真正要删除的节点是否是根节点,是否是黑色节点。因为红色节点和根节点删除不会调整树形。如果删除的是黑色
节点,那么要看替换他的节点(这里的替换一定是左子树树根,因为如果有右子树,那么被删除的也不会是这个节点,记住二叉查找树的删除过程)是否是黑色节点(这里如果左
子树为空,那他也是黑色节点)。如果是黑色节点,那么一定要调整树的结构,否则就直接染色。调整树结构时要考虑的情况就非常多了。一共有9种情况需要考虑。
下面是代码部分,删除时如何调整在代码注释中。至于insert操作,看看文献就应该会做了。
- /*
- * create RBNode class for construction RBTree
- * create by chico chen
- * date: 2008/09/04
- * 如需转载注明出处
- */
-
- template< class T>
- #define RED 0
- #define BLACK 1
- class RBNode
- {
- public :
-
- T data;
- RBNode
* left; - RBNode
* right; - RBNode
* parent; - int color;
-
- RBNode(T& data)
- {
- this ->data = data;
- left = NULL;
- right = NULL;
- parent = NULL;
- color = RED;
- }
- RBNode(T& data, RBNode
* left, RBNode * right, RBNode * parent) - {
- this ->data = data;
- this ->left = left;
- this ->right = right;
- this ->parent = parent;
- color = RED;
- }
-
- ~RBNode()
- {
- this ->left = this ->right = this ->parent = NULL;
- color = RED;
- }
- };
下面是红黑树代码
- /*
- * this is red-black-tree code
- * this code is not efficent in inserting
-
- * create by chico chen
- * date: 2008/09/04
- * 如需转载注明出处
- */
-
- #include “RBNode.h”
-
- template< class T>
- class RBTree
- {
-
- private :
- RBNode
* root; - public :
- RBTree()
- {
- this ->root = NULL;
- }
- ~RBTree()
- {
- clearTree( this ->root);
- }
-
-
-
- void print()
-
-
- {
- print( this ->root,0);
- }
-
-
-
-
-
- void insert(T& data)
-
-
-
-
- {
-
- RBNode
* node = new RBNode (data);
- RBNode
- insertNode(node);
- }
-
- void deleteKey(T& data)
- {
- deleteNode(data);
- }
-
-
- bool RBTreeTest()
-
- {
- try
- {
- getBlackNum( this ->root);
-
- }
- catch (…)
- {
- return false ;
- }
- return true ;
- }
-
- private :
-
-
- void print(RBNode
* subRoot, int num)
- void print(RBNode
-
- {
- if (subRoot != NULL)
- {
- print(subRoot->right,num+3);
- for ( int i = 0; i < num; i++)
- {
- cout << " " ;
- }
- cout << subRoot->data<< “(” <
color<< “)” <<endl; - print(subRoot->left,num+3);
- }
- }
-
- void clearTree(RBNode
* subRoot)
- void clearTree(RBNode
- {
- if (subRoot == NULL)
- return ;
- clearTree(subRoot->left);
- clearTree(subRoot->right);
- delete subRoot;
- }
-
- RBNode
* deleteMin(RBNode * subRoot,RBNode ** parent)
- RBNode
- {
-
- while (subRoot != NULL)
- {
- parent = &subRoot;
- if (subRoot->right != NULL)
- {
- subRoot = subRoot->right;
- }
- else
- {
- break ;
- }
- }
- return subRoot;
- }
-
- void deleteNode(T& data)
- {
- if (root == NULL)
- {
- throw “Empty tree” ;
- }
- RBNode
* subRoot = root; - while (subRoot != NULL)
- {
- if (subRoot->data > data)
- {
- subRoot = subRoot->left;
- }
- else if (subRoot->data < data)
- {
- subRoot = subRoot->right;
- }
- else
- {
- // find the data
- // use the midOrder last one which is before the data node to replace
- RBNode
* inParent = subRoot; - RBNode
* deleteNode = deleteMin(subRoot->left,&inParent); - RBNode
* realDelete = NULL; - if (deleteNode != NULL)
- {
- subRoot->data = deleteNode->data; // copy
- realDelete = deleteNode;
- //real delete
- }
- else
- {
- realDelete = subRoot;
- //real delete
- }
- if (realDelete->parent == NULL)
- {
- // delete root
- delete realDelete;
- }
- else
- {
- // nothing at realDelete->right
- RBNode
* parent = realDelete->parent; - RBNode
* subATree = NULL; - if (parent->left == realDelete)
- {
- parent->left = realDelete->left;
- }
- else
- {
- parent->right = realDelete->left;
- }
- subATree = realDelete->left;
- if (realDelete->left != NULL)
- {
- realDelete->left->parent = parent;
- }
- int color = realDelete->color;
- delete realDelete;
- if (color == BLACK &&
- (subATree == NULL || subATree->color == BLACK))
- {
-
-
- deleteRebuild(subATree,parent);
-
- }
- else if (color == BLACK && subATree->color == RED)
- {
- subATree->color = BLACK;
- }
- else
- {
- // do nothing
- }
- break ;
- }
-
- }
- }
- }
-
-
- /* delete them if you want
-
-
- // x® c®
- // / / / /
- // `a(b) b(b) --> x(b) b(b)
- // / /
- // c® a(b)
- // LRL means L-> double black is at left, and rotate is RL
- RBNode
* LRLCaseA(RBNode * x) - {
- RLRotate(x,x->right,x->right->left);
- x->color = BLACK;
- return x->parent;
-
- }
-
-
- // x® b®
-
- // / / / /
- // `a(b) b(b) --> x(b) c(b)
- // / /
- // c® a(b)
- RBNode
* LLLCaseA(RBNode * x) - {
- RRRotate(x,x->right);
- x->color = BLACK;
- x->parent->color = RED;
- x->parent->right->color = BLACK;
- return x->parent;
- }
-
- // x® b®
- // / / / /
- // b(b) `a(b)–> c(b) x(b)
- // / /
- // c® a(b)
- RBNode
* RLLCaseA(RBNode * x) - {
- LLRotate(x,x->left);
- x->color = BLACK;
- x->parent->color = RED;
- x->parent->left->color = BLACK;
- return x->parent;
- }
-
-
- // x® c®
-
- // / / / /
- // b(b) `a(b)–> b(b) x(b)
- // / /
- // c® a(b)
- RBNode
* RLRCaseA(RBNode * x) - {
- LRRotate(x,x->left,x->left->right);
- x->color = BLACK;
-
- return x->parent;
- }
-
-
- // x® x(b)
-
- // / / / /
- // `a(b) c(b) -> a(b) c®
- // / / / /
- // d(b) e(b) d(b) e(b)
- RBNode
* LCaseB(RBNode * x) - {
- x->color = BLACK;
- x->right->color = RED;
- }
-
- // x® x(b)
- // / / / /
- // c(b) `a(b) -> c® a(b)
- // / / / /
- // d(b) e(b) d(b) e(b)
- RBNode
* RCaseB(RBNode * x) - {
- x->color = BLACK;
- x->left->color = RED;
- }
-
- // x(b) c(b)
- // / / / /
- // `a(b) c® -> x® e(b)
- // / / / /
- // d(b) e(b) `a(b) d(b)
- RBNode
* LCaseC(RBNode * x) - {
- RRRotate(x,x->right);
- x->color = RED;
- x->parent->color = BLACK;
- return x->parent;
- }
-
- // x(b) c(b)
- // / / / /
- // c® `a(b) -> d(b) x®
- // / / / /
- // d(b) e(b) e(b) `a(b)
- RBNode
* RCaseC(RBNode * x) - {
- LLRotate(x,x->left);
- x->color = RED;
- x->parent->color = BLACK;
- return x->parent;
- }
-
- */
-
- bool isBlack(RBNode
* node)
- bool isBlack(RBNode
- {
-
- if (node == NULL || node->color == BLACK)
- return true ;
- return false ;
- }
-
- void rebuild(RBNode
* node)
- void rebuild(RBNode
- {
- if (node->parent->data > node->data)
- {
- node->parent->left = node;
- }
- else
- {
- node->parent->right = node;
- }
- }
-
-
- /*
-
- * There are 9 cases we will meet. The cases of the double black node at the right is ignored.
- * (b) means black node, (db) means double black node, ® means red node
- * 1. (b) 2 (b) 3 (b)
- * / / / / / /
- * (db) (b) (db) (b) (db) (b)
- * / / / / / /
- * (b) (b) ® (b) (b) ®
-
- * 4. (b) 5 (b) 6 ®
- * / / / / / /
- * (db) (b) (db) ® (db) (b)
- * / / / / / /
- * ® ® (b) (b) (b) (b)
-
- * 7. ® 8 ® 9 ®
- * / / / / / /
- * (db) (b) (db) (b) (db) (b)
- * / / / / / /
- * ® (b) (b) ® ® ®
-
- * case 1,6: up the black, if the parent is black then call the function again until the
- * double black node is root, else blacken the parent.
- * case 2,4,7,9: call the RLRotate, if the parent of the double
- * node is black, up the black and call the function again, else
- * blacken the parent.
- * case 3,8: call the LLRotate, the same as case 2.
- * case 5: call LLRotate, change as (b) then end.
- * / /
- * (b) (b)
- * / /
- * (b) ®
-
- */
- void deleteRebuild(RBNode
* node,RBNode * parent) - {
- if (parent == NULL)
- {
- // root, delete the black
- return ;
- }
- if (parent->left == node)
- {
- RBNode
* brother = parent->right; - RBNode
* nephewA = brother->left; - RBNode
* nephewB = brother->right; -
- if (isBlack(nephewA) && isBlack(nephewB) && isBlack(brother))
- {
- // case 1,6
- brother->color = RED;
- if (parent->color == BLACK)
- {
- deleteRebuild(parent,parent->parent);
- }
- else
- {
- parent->color = BLACK;
- return ;
- }
-
- }
-
- else if (!isBlack(nephewA))
- {
- // case 2,4,7,9
- RBNode
* tempRoot = RLRotate(parent,brother,nephewA); - // rebuild
- rebuild(tempRoot);
-
- }
- else if (!isBlack(nephewB))
- {
- // case 3,8
- RBNode
* tempRoot = RRRotate(parent,brother); - rebuild(tempRoot);
- nephewB->color = BLACK;
- brother->color = RED;
- }
- else if (!isBlack(brother))
- {
- // case 5
- RBNode
* tempRoot = RRRotate(parent,brother); - rebuild(tempRoot);
- brother->color = BLACK;
- nephewA->color = RED;
- return ;
- }
- else
- {
- // unknown
- throw “none excption, about there is no red or black” ;
- }
-
- if (parent->color == BLACK)
- {
- // case 2,3,4
- deleteRebuild(parent,parent->parent);
- }
- else
- {
- // case 7,8,9
- parent->color = BLACK;
- }
-
- }
- else
- {
- RBNode
* brother = parent->left; - RBNode
* nephewA = brother->right; - RBNode
* nephewB = brother->left; -
- if (isBlack(nephewA) && isBlack(nephewB) && isBlack(brother))
- {
- brother->color = RED;
- if (parent->color == BLACK)
- {
- deleteRebuild(parent,parent->parent);
- }
- else
- {
- parent->color = BLACK;
- return ;
- }
- }
- else if (!isBlack(nephewA))
- {
- RBNode
* tempRoot = LRRotate(parent,brother,nephewA); - // rebuild
- rebuild(tempRoot);
-
- }
- else if (!isBlack(nephewB))
- {
- RBNode
* tempRoot = LLRotate(parent,brother); - rebuild(tempRoot);
- nephewB->color = BLACK;
- brother->color = RED;
- }
- else if (!isBlack(brother))
- {
- RBNode
* tempRoot = LLRotate(parent,brother); - rebuild(tempRoot);
- nephewA->color = RED;
- brother->color = BLACK;
- return ;
- }
- else
- {
- throw “none excption, about there is no red or black” ;
- }
-
- if (parent->color == BLACK)
- {
- deleteRebuild(parent,parent->parent);
- }
- else
- {
- parent->color = BLACK;
- }
-
- }
-
- }
-
-
- void insertNode(RBNode
* node)
- void insertNode(RBNode
-
- {
-
- if (root == NULL)
- {
- root = node;
- node->color = BLACK;
- return ;
- }
- RBNode
* subRoot = root; - RBNode
* insertPoint = NULL; - while (subRoot!=NULL)
- {
- insertPoint = subRoot;
- if (subRoot->data > node->data)
- {
- // insert left
- subRoot = subRoot->left;
-
- }
- else if (subRoot->data < node->data)
- {
- subRoot = subRoot->right;
- }
- else
- {
- throw “same key” ;
- }
- }
-
-
- if (insertPoint->data > node->data)
-
- {
- insertPoint->left = node;
- }
- else
- {
- insertPoint->right = node;
- }
- node->parent = insertPoint;
-
-
- insertRebuild(node);
-
-
- }
-
- // return the subRoot
- // a b
- // / / /
- // b -> c a
- // /
- // c
- RBNode
* LLRotate(RBNode * a, RBNode * b) - {
- if (b->right != NULL)
- {
- b->right->parent = a;
-
- }
- a->left = b->right;
- b->right = a;
- b->parent = a->parent;
- a->parent = b;
- return b;
- }
-
- // return the subRoot
- // a b
- // / / /
- // b -> a c
- // /
- // c
- RBNode
* RRRotate(RBNode * a, RBNode * b) - {
- if (b->left != NULL)
- {
- b->left->parent = a;
-
- }
- a->right = b->left;
- b->left = a;
- b->parent = a->parent;
- a->parent = b;
-
-
- return b;
-
- }
-
-
- // return the subRoot
-
- // a c
- // / / /
- // b -> a b
- // / /
- // c d
- // /
- // d
- RBNode
* RLRotate(RBNode * a, RBNode * b, RBNode * c) - {
-
- if (c->right != NULL)
- {
- c->right->parent = b;
-
- }
- b->left = c->right;
- c->right = b;
- b->parent = c;
- if (c->left != NULL)
- {
- c->left->parent = a;
-
- }
- a->right = c->left;
- c->left = a;
- c->parent = a->parent;
- a->parent = c;
-
- return c;
- }
-
- // return the subRoot
- // a c
- // / / /
- // b -> b a
- // / /
- // c d
- // /
- // d
- RBNode
* LRRotate(RBNode * a, RBNode * b, RBNode * c) - {
- if (c->left != NULL)
- {
- c->left->parent = b;
-
-
- }
-
- b->right = c->left;
- c->left = b;
- b->parent = c;
- if (c->right!= NULL)
- {
- c->right->parent = a;
-
- }
- a->left = c->right;
- c->right = a;
- c->parent = a->parent;
- a->parent = c;
-
- return c;
- }
-
- // node is not the root
- void insertRebuild(RBNode
* node) - {
- RBNode
* parent = NULL; - RBNode
* grandParent = NULL; - while (node->parent != NULL)
- {
- parent = node->parent;
-
- if (parent->color == RED) // here means there must be a grandparent
- {
- grandParent = parent->parent;
- grandParent->color = BLACK;
-
- if (grandParent->left == parent)
- {
- if (parent->left == node)
- {
- //LLRotate
- node->color = BLACK;
- node = LLRotate(grandParent,parent);
-
- }
- else
- {
- //LRRotate
- parent->color = BLACK;
- node = LRRotate(grandParent,parent,node);
-
- }
-
- }
- else
- {
-
- if (parent->left == node)
- {
- //RLRotate
- parent->color = BLACK;
- node = RLRotate(grandParent,parent,node);
- }
- else
- {
- //RRRotate
- node->color = BLACK;
- node = RRRotate(grandParent,parent);
- }
- }
- }
- else
- {
- break ;
- }
- }
-
- if (node->parent == NULL)
- {
- node->color = BLACK;
- this ->root = node;
- }
- else
- {
- rebuild(node);
- /*if(node->parent->data > node->data)
- {
- node->parent->left = node;
- }
- else
- {
- node->parent->right = node;
- }*/
- }
- }
-
-
-
-
- int getBlackNum(RBNode
* subRoot)
- int getBlackNum(RBNode
-
-
-
- {
- if (subRoot == NULL)
- {
- return 1;
- }
- int left = getBlackNum(subRoot->left);
- int right = getBlackNum(subRoot->right);
- if (left != right)
- {
- throw “wrong” ;
- }
- if (subRoot->color == BLACK)
- {
-
- return 1+left;
- }
- else
- {
- return left;
- }
-
- }
- };