红黑树是一种二叉排序树,是AVL树的变种, 红黑树通过一些着色法则确保没有一条路径会比其它路径长出两倍,因而达到接近平衡目的。使其比二叉查找树更有效率。
红黑树的性质如下:
1) 每一个节点或者着红色,或者着成黑色.4) 从一个节点到一个NULL指针的每一条路径必须包含相同数目的黑色节点.
红黑树
红黑树的插入会出现两个红结点相邻的情况,即不平衡。
不平衡可分为以下三种情况:
case 1(俗称 “红黑红红”):
这种情况下,只需改变节点的颜色,然后以新的根节点(图中为new z),作为起始节点,向上继续调整(此时new z的父节点可能为红色,因此需要继续调整)。
case 2,3 (俗称“黑红红"):
处理时,可先把case2先转化为case3,然后调整。因调整后不会出现不平衡的情况,无需继续向上调整。
删除节点:
首先,我们应该想明白,删除一个节点(Z),并不等于真的删除这个节点(Z)。而是像二叉树那样,拿当前节点的次小节点(Y)来填充,如果这个次小节点(Y)是红色的,则比较好处理,只需把Y的左子树(或右子树)取代Y的位置即可;但是如果(Y)为黑色,则处理起来较麻烦。因为,删除一个黑色节点时,会造成这个黑色结点下面的若干个节点的黑色高度-1,从而不平衡。
解决方法就是调整:想方设法把下面节点的黑色高度保持不变。
严蔚敏版的《数据结构与算法》与算法中的调整方法类似于穷举,把周围节点的红黑情况都列出来,然后调整。这种方法很直观,比较好理解,但是因为周围节点红黑情况太多,大约需要14个if else语句才能处理。太耗费耐心,精力。
另一种调整方法是《算法导论》里的,它把删除一个节点后造成的不平衡分为四类。为了说明方便,用X代表删除Y后补上去的结点(重色结点),w代表X的兄弟结点。
case 1:
转化为之后,X仍然是重色结点,继续进行转换。
case 2:
转化之后,再把X染为黑色即可结束。
case 3:
转化之后,x仍未重色结点,需要继续进行转换。
case 4:
转化之后,X指向root,结束。
也就是说,case 3、4是转化的出口,case 1、2只需先转化为case 3、4即可解决。
代码编写:
以前写过二叉树的程序,但是从未遇到过需要父节点的。这不,没有考虑周全就开始写代码,结果写代码的时间远远出乎意料。竟然用了大约10个小时来写红黑树。其中大部分的时间都浪费在了debug上。一遍又一遍根据输入输出,断点等找程序的bug,非常地痛苦。最后才意识到一个最大的bug:改动每一个左右节点的指向时,都要同时改变它的孩子结点的父节点指针。
代码:
#include<assert.h> #include<iostream> #include<fstream> #include<algorithm> #include<time.h> #include<stack> using namespace std; //ºìºÚÊ÷œáµã //E ΪœÚµãŒüÖµµÄÊýŸÝÀàÐÍ template<class E> class RBNode { public: E key; //key of the RBNode RBNode *left; //pointer to the left child of this RBNode RBNode *right; //pointer to the right child of this RBNode RBNode *parent; //pointer to the parent child of this RBNode char color; //the RBNode's color 'B' is black, 'R' is red RBNode(E k):key(k){left=right=NULL;}; //int height; }; template<class E> class RBTree { private: RBNode<E> * root; //root of this RBTree RBNode<E> * balance(RBNode<E> * A_node); void RBTree<E>::leftRotate(RBNode<E> *b); //leftRotate void RBTree<E>::rightRotate(RBNode<E> *d); //rightRotate void removeFix(RBNode<E> *x); //fix the RBtree when remove a black node void inorder(ostream &out,RBNode<E> *p); //output the keys in the RBTree inorder public: RBTree(); //construtor ~RBTree(); RBNode<E> * search(E key); //search the RBNode whose key equals "key" RBNode<E> * insert(E key); //insert a RBNode values "key" into the RBTree RBNode<E> * remove(E key); //delete the RBNode whose key is "key" void output(ostream &out); }; //construtor template<class E> RBTree<E>::RBTree( ) { root=NULL; } //destructor template<class E> RBTree<E>::~RBTree( ) { } //search the RBNode whose key equals "key" //@param key the key of RBNode //return return the pointer to the RBNode of key,if failed,return NULL template<class E> RBNode<E> *RBTree<E>::search(E key) { RBNode<E> *p=root; while(p!=NULL) { if(p->key==key) //== { break; } else if(p->key>key) //in left subtree { p=p->left; } else if(p->key<key) //int right subtree { p=p->right; } } return p; } //balance the red node //@param node //return the root of balanced tree template<class E> RBNode<E> *RBTree<E>::balance(RBNode<E> * A_node) { if(A_node==root){A_node->color='B';return A_node;}; RBNode<E> *B_node=A_node->parent; if(B_node->color=='B')return B_node; RBNode<E> *C_node=B_node->parent; if(C_node==NULL){ B_node->color='B';return B_node;}; RBNode<E> *temp_root=C_node->parent; if(B_node==C_node->left) { if(C_node->right!=NULL&&C_node->right->color=='R') //RBRR { C_node->right->color='B'; C_node->color='R'; B_node->color='B'; return C_node; } else //BRR { if(A_node==B_node->right) //swap A_node ,B_node { B_node->parent=A_node; A_node->parent=C_node; C_node->left=A_node; RBNode<E> *temp=A_node->left; if(A_node->left)A_node->left->parent=B_node; A_node->left=B_node; B_node->right=temp; temp=A_node; A_node=B_node; B_node=temp; } if(temp_root!=NULL) { B_node->parent=temp_root; if(temp_root->left==C_node) temp_root->left=B_node; else temp_root->right=B_node; } else { B_node->parent=NULL; root=B_node; } B_node->color='B'; C_node->color='R'; C_node->left=B_node->right; if(B_node->right)B_node->right->parent=C_node; B_node->right=C_node; C_node->parent=B_node; A_node->parent=B_node; return B_node; } } else if(B_node==C_node->right) { if(C_node->left!=NULL&&C_node->left->color=='R') //RBRR { C_node->left->color='B'; C_node->color='R'; B_node->color='B'; return C_node; } else { if(A_node==B_node->left) { B_node->parent=A_node; A_node->parent=C_node; C_node->right=A_node; RBNode<E> *temp=A_node->right; if(A_node->right)A_node->right->parent=B_node; A_node->right=B_node; B_node->left=temp; temp=A_node; A_node=B_node; B_node=temp; } if(temp_root!=NULL) { B_node->parent=temp_root; if(temp_root->left==C_node) temp_root->left=B_node; else temp_root->right=B_node; } else { B_node->parent=NULL; root=B_node; } C_node->color='R'; B_node->color='B'; C_node->right=B_node->left; if(B_node->left)B_node->left->parent=C_node; B_node->left=C_node; C_node->parent=B_node; A_node->parent=B_node; return B_node; } } } template<class E> RBNode<E> *RBTree<E>::insert(E key) { if(root==NULL) { root=new RBNode<E>(key); root->color='B'; root->parent=NULL; return root; } RBNode<E> *p=root; RBNode<E> *q=root; while(q!=NULL) { if(q->key==key) //== { return q; //can not insert } else if(q->key>key) //in left subtree { p=q; q=q->left; } else if(q->key<key) //int right subtree { p=q; q=q->right; } } q=new RBNode<E>(key); q->color='R'; q->parent=p; if(q->key>p->key) { assert(p->right==NULL); p->right=q; } else { assert(p->left==NULL); p->left=q; } while(q->color=='R') //balance { q=balance(q); } return q; } //inorder visit a tree template<class E> void RBTree<E>::inorder(ostream &out,RBNode<E> *p) { if(p==NULL)return; inorder(out,p->left); out<<p->key<<","; /*if(p->parent==NULL) // output the black-height of the leaf node,if all the black p->height=1; //is the same num,it implements the program is right,if not it is wrong else { if(p->color=='B') p->height=p->parent->height+1; else p->height=p->parent->height; } if(p->left==NULL&&p->right==NULL) cout<<"black height:"<<p->height<<endl;*/ /*if(p->left) out<<"left "<<p->left->key; if(p->right) out<<"right "<<p->right->key; if(p->parent) out<<"parent "<<p->parent->key<<" ";*/ inorder(out,p->right); } //output the RBTree //@param out, the output IO stream template<class E> void RBTree<E>::output(ostream &out) { inorder(out,root); out<<endl; } template<class E> void RBTree<E>::leftRotate(RBNode<E> *b) { RBNode<E> *d=b->right; if(d==NULL)return; RBNode<E> *temp_root=b->parent; RBNode<E> *c=d->left; b->right=c; if(c!=NULL) c->parent=b; d->left=b; b->parent=d; d->parent=temp_root; if(temp_root==NULL) { root=d; } else { if(temp_root->left==b) temp_root->left=d; else if(temp_root->right==b) temp_root->right=d; } } template<class E> void RBTree<E>::rightRotate(RBNode<E> *A) { /*RBNode<E> *b=d->parent; RBNode<E> *c=d->left; d->left=c->right; if(c->right!=NULL)c->right->parent=d; c->right=d; d->parent=c; c->parent=b; if(b==NULL) root=c; else { if(b->left==d) b->left=c; else if(b->right==d) b->right=c; } */ RBNode<E> * B; B = A->left; if (NULL == B) return; A->left = B->right; if (NULL != B->right) B->right->parent = A; B->parent = A->parent; // ÕâÑùÈýžöÅжÏÁ¬ÔÚÒ»Æð±ÜÃâÁËA->parent = NULLµÄÇé¿ö if (A == root) { root = B; } else if (A == A->parent->left) { A->parent->left = B; } else { A->parent->right = B; } A->parent = B; B->right = A; } template<class E> void RBTree<E>::removeFix(RBNode<E> *x) { RBNode<E> *w; while(x!=root&&x->color=='B') { if(x==x->parent->left) { w=x->parent->right; if(w==NULL) continue; //case 1 if(w->color=='R') { x->parent->color='R'; w->color='B'; leftRotate(x->parent); w=x->parent->right; } //case 2 if(w->left!=NULL&&w->left->color=='B'&&w->right!=NULL&&w->right->color=='B') { w->color='R'; x=x->parent; } else { //case 3 if(w->right!=NULL&&w->right->color=='B') { w->color='R'; w->left->color='B'; rightRotate(w); w=x->parent->right; } w->color=x->parent->color; x->parent->color='B'; w->right->color='B'; leftRotate(x->parent); x=root; } } else if(x==x->parent->right) //Symmetric { w=x->parent->left; if(w==NULL) continue; //case 1 if(w->color=='R') { w->color='B'; x->parent->color='R'; rightRotate(x->parent); w=x->parent->left; } //case 2 if(w->left!=NULL&&w->left->color=='B'&&w->right!=NULL&&w->right->color=='B') { w->color='R'; x=x->parent; } else { if(w->left->color=='B') { w->right->color='B'; w->color='R'; leftRotate(w); w=x->parent->left; } //case 4 w->color=x->parent->color; x->parent->color='B'; w->left->color='B'; rightRotate(x->parent); x=root; } } } x->color='B'; } //remove the node whose key equals key //@param key,the key of the node to be removed //return the node was remove actually template<class E> RBNode<E> *RBTree<E>::remove(E key) { RBNode<E> *z=this->search(key); //find the node to be removed if(z==NULL)return NULL; //the node do not exist in this tree RBNode<E> *y; if(z->left==NULL||z->right==NULL) { y=z; } else { y=z->right; while(y->left!=NULL) { y=y->left; } } RBNode<E> *x; //xÊÇyµÄ×ÓÊ÷,¿ÉÄÜΪNULL if(y->left!=NULL) { x=y->left; } else { x=y->right; } if(x!=NULL) x->parent=y->parent; if(y->parent==NULL) root=x; else if(y==y->parent->left) y->parent->left=x; else if(y==y->parent->right) y->parent->right=x; if(y->key!=z->key) z->key=y->key; if(y->color=='B'&&x!=NULL) //if the actually removed node is black removeFix(x); //fix to balance free(y); return root; } int main() { RBTree<int> *rbtTree=new RBTree<int>(); ofstream cout("output.txt"); //ifstream cin("input.txt"); int n=50; int *data=new int[n]; srand((unsigned int )time(0)); for(int i=0;i<n;) { data[i]=rand()%50000; int j; for(j=0;j<i;j++) { if(data[j]==data[i]) break; } if(j==i) i++; } //int data[]={122,328, }; for(int i=0;i<n;i++) { cout<<data[i]<<","; } cout<<endl; for(int i=0;i<n;i++) { rbtTree->insert(data[i]); } rbtTree->output(cout); //sort(data,data+n); for(int i=0;i<n;i++) { cout<<data[i]<<","; } cout<<endl; for(int i=0;i<n;i++) { rbtTree->remove(data[i]); rbtTree->output(cout); } return 0; }