在网上搜索了很多红黑树的资源,发现自己看代码的能力还是有些欠缺。很多都看不懂,后来找到一篇英文红黑树文献,终于弄明白了红黑树的删除插入是怎么做的。但是那片文献好像还有些漏洞,其中有一种删除情况,他并没有考虑到。如果大家想看的话可以搜索下 "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<T>* left;
- RBNode<T>* right;
- RBNode<T>* parent;
- int color;
- RBNode(T& data)
- {
- this->data = data;
- left = NULL;
- right = NULL;
- parent = NULL;
- color = RED;
- }
- RBNode(T& data, RBNode<T>* left, RBNode<T>* right, RBNode<T>* 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<T>* root;
- public:
- RBTree()
- {
- this->root = NULL;
- }
- ~RBTree()
- {
- clearTree(this->root);
- }
- void print()
- {
- print(this->root,0);
- }
- void insert(T& data)
- {
- RBNode<T>* node = new RBNode<T>(data);
- insertNode(node);
- }
- void deleteKey(T& data)
- {
- deleteNode(data);
- }
- bool RBTreeTest()
- {
- try
- {
- getBlackNum(this->root);
- }
- catch(...)
- {
- return false;
- }
- return true;
- }
- private:
- void print(RBNode<T>* subRoot, int num)
- {
- if(subRoot != NULL)
- {
- print(subRoot->right,num+3);
- for(int i = 0; i < num; i++)
- {
- cout << " ";
- }
- cout << subRoot->data<<"("<<subRoot->color<<")"<<endl;
- print(subRoot->left,num+3);
- }
- }
- void clearTree(RBNode<T>* subRoot)
- {
- if(subRoot == NULL)
- return;
- clearTree(subRoot->left);
- clearTree(subRoot->right);
- delete subRoot;
- }
- RBNode<T>* deleteMin(RBNode<T>* subRoot,RBNode<T>** parent)
- {
- 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<T>* 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<T>* inParent = subRoot;
- RBNode<T>* deleteNode = deleteMin(subRoot->left,&inParent);
- RBNode<T>* 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<T>* parent = realDelete->parent;
- RBNode<T>* 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(r) c(r)
- // / / / /
- // `a(b) b(b) --> x(b) b(b)
- // / /
- // c(r) a(b)
- // LRL means L-> double black is at left, and rotate is RL
- RBNode<T>* LRLCaseA(RBNode<T>* x)
- {
- RLRotate(x,x->right,x->right->left);
- x->color = BLACK;
- return x->parent;
- }
- // x(r) b(r)
- // / / / /
- // `a(b) b(b) --> x(b) c(b)
- // / /
- // c(r) a(b)
- RBNode<T>* LLLCaseA(RBNode<T>* x)
- {
- RRRotate(x,x->right);
- x->color = BLACK;
- x->parent->color = RED;
- x->parent->right->color = BLACK;
- return x->parent;
- }
- // x(r) b(r)
- // / / / /
- // b(b) `a(b)--> c(b) x(b)
- // / /
- // c(r) a(b)
- RBNode<T>* RLLCaseA(RBNode<T>* x)
- {
- LLRotate(x,x->left);
- x->color = BLACK;
- x->parent->color = RED;
- x->parent->left->color = BLACK;
- return x->parent;
- }
- // x(r) c(r)
- // / / / /
- // b(b) `a(b)--> b(b) x(b)
- // / /
- // c(r) a(b)
- RBNode<T>* RLRCaseA(RBNode<T>* x)
- {
- LRRotate(x,x->left,x->left->right);
- x->color = BLACK;
- return x->parent;
- }
- // x(r) x(b)
- // / / / /
- // `a(b) c(b) -> a(b) c(r)
- // / / / /
- // d(b) e(b) d(b) e(b)
- RBNode<T>* LCaseB(RBNode<T>* x)
- {
- x->color = BLACK;
- x->right->color = RED;
- }
- // x(r) x(b)
- // / / / /
- // c(b) `a(b) -> c(r) a(b)
- // / / / /
- // d(b) e(b) d(b) e(b)
- RBNode<T>* RCaseB(RBNode<T>* x)
- {
- x->color = BLACK;
- x->left->color = RED;
- }
- // x(b) c(b)
- // / / / /
- // `a(b) c(r) -> x(r) e(b)
- // / / / /
- // d(b) e(b) `a(b) d(b)
- RBNode<T>* LCaseC(RBNode<T>* x)
- {
- RRRotate(x,x->right);
- x->color = RED;
- x->parent->color = BLACK;
- return x->parent;
- }
- // x(b) c(b)
- // / / / /
- // c(r) `a(b) -> d(b) x(r)
- // / / / /
- // d(b) e(b) e(b) `a(b)
- RBNode<T>* RCaseC(RBNode<T>* x)
- {
- LLRotate(x,x->left);
- x->color = RED;
- x->parent->color = BLACK;
- return x->parent;
- }
- *
- */
- bool isBlack(RBNode<T>* node)
- {
- if(node == NULL || node->color == BLACK)
- return true;
- return false;
- }
- void rebuild(RBNode<T>* node)
- {
- 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, (r) means red node
- * 1. (b) 2 (b) 3 (b)
- * / / / / / /
- * (db) (b) (db) (b) (db) (b)
- * / / / / / /
- * (b) (b) (r) (b) (b) (r)
- *
- * 4. (b) 5 (b) 6 (r)
- * / / / / / /
- * (db) (b) (db) (r) (db) (b)
- * / / / / / /
- * (r) (r) (b) (b) (b) (b)
- *
- * 7. (r) 8 (r) 9 (r)
- * / / / / / /
- * (db) (b) (db) (b) (db) (b)
- * / / / / / /
- * (r) (b) (b) (r) (r) (r)
- *
- * 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) (r)
- *
- */
- void deleteRebuild(RBNode<T>* node,RBNode<T>* parent)
- {
- if(parent == NULL)
- {
- // root, delete the black
- return;
- }
- if(parent->left == node)
- {
- RBNode<T>* brother = parent->right;
- RBNode<T>* nephewA = brother->left;
- RBNode<T>* 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<T>* tempRoot = RLRotate(parent,brother,nephewA);
- // rebuild
- rebuild(tempRoot);
- }
- else if(!isBlack(nephewB))
- {
- // case 3,8
- RBNode<T>* tempRoot = RRRotate(parent,brother);
- rebuild(tempRoot);
- nephewB->color = BLACK;
- brother->color = RED;
- }
- else if(!isBlack(brother))
- {
- // case 5
- RBNode<T>* 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<T>* brother = parent->left;
- RBNode<T>* nephewA = brother->right;
- RBNode<T>* 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<T>* tempRoot = LRRotate(parent,brother,nephewA);
- // rebuild
- rebuild(tempRoot);
- }
- else if(!isBlack(nephewB))
- {
- RBNode<T>* tempRoot = LLRotate(parent,brother);
- rebuild(tempRoot);
- nephewB->color = BLACK;
- brother->color = RED;
- }
- else if(!isBlack(brother))
- {
- RBNode<T>* 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<T>* node)
- {
- if(root == NULL)
- {
- root = node;
- node->color = BLACK;
- return;
- }
- RBNode<T>* subRoot = root;
- RBNode<T>* 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<T>* LLRotate(RBNode<T>* a, RBNode<T>* 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<T>* RRRotate(RBNode<T>* a, RBNode<T>* 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<T>* RLRotate(RBNode<T>* a, RBNode<T>* b, RBNode<T>* 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<T>* LRRotate(RBNode<T>* a, RBNode<T>* b, RBNode<T>* 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<T>* node)
- {
- RBNode<T>* parent = NULL;
- RBNode<T>* 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<T>* subRoot)
- {
- 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;
- }
- }
- };