红黑树

来源:互联网 发布:overlay网络原理 编辑:程序博客网 时间:2024/05/22 09:00

  红黑树的性质:

                         1.每个结点或是红色的,或是黑色的

                         2.根结点都是黑色的

                         3.如果一个结点是红色的,则它的两个子结点都是黑色的。

                         4.对于每个结点,从该节点到其所有后代的NULL的简单路径上,均包含相同数目的黑色结点

红黑树的插入:

          对于红黑树T,将新结点z插到T中,就像普通的二叉查找树样,先把z插入到树中,然后再把z着为红色(因为若把该节点涂成黑色,则将会建立一条更长的黑结点路径)。若z的父结点为黑色,则不会破坏红黑树性质,完成插入;若父结点为红色,则破坏红黑树的性质。当T为空,那么在就是跟结点,违反了性质2;若T不为空,违反性质3。

红黑树的插入分下面几种情况(T为空时,就不列出来,因为直接把z结点作为根结点,并且把z涂成黑色即可)圆圈表示黑色,正方形表示红色:

一、z结点的父结点是z祖父的左儿子(其中的z指向新插入的结点k3)

(一)z的叔结点是空

1.  z是左儿子

                                                       

2.  z是右儿子

                                                    

(二) z的叔结点不为空

1.  z的叔结点为红色,如下图通过变换,将z的指针上移,指向k1。然后以k1为新的z进入下次循环,调整红黑树,使得树满足红黑树的性质

                                                   

2.  z的叔结点为黑色,其中分为,z为左儿子和右儿子,其变换图下图。当z为右儿子时,z指向k2,通过变换转化为z的结点为左儿子的情况。

                                           

对于上述的插入,当为(一)中的两种情况,通过变换后,满足红黑树的性质。在编程中通过设置flag标示来结束循环;当为(二)中2的第一种情况(即z为左儿子),通过变换后,满足红黑树的性质,通过判断z的父结点是否为黑色来结束循环。其他情况中若z指向根结点,则把z的颜色涂成黑色,结束循环。

当z的父结点为z祖父结点的右儿子时,可以类似z父结点为左儿子的进行类似的变换,使得满足红黑树的性质。

红黑树的删除

     红黑树的删除比红黑树的插入复杂的多。首先由二叉查找树删除的性质可知,删除的结点z一般为:z无儿子、z仅有一个左儿子、z仅有一个右儿子。因为当删除的结点有两个儿子时,总可以通过查找该结点的后继z,后继中的元素element替换该节点中的元素element。这样就把删除转化为上述的三种中的某一种情况。

下面考虑删除中的几种情况:删除结点为z

一、z为红色时

      这个比较简单,由上分析可知z最多只有一个儿子,因为z为红色,要有儿子必为两个黑色儿子,这与上面分析矛盾,所以z为红色时无儿子。删除时直接删除即可,不会破坏红黑树的性质。

二、z为黑色时,且z有一个儿子或者z为根节点无儿子。

    当z有一个儿子时,该结点必为红色,若为黑色,由于z是只有一个儿子的,其不满足红黑树的性质4。删除方法:直接把z儿子中的元素element代替z中的元素element,然后把z儿子结点删除;若z为根结点直接删除即可。

三、z为黑色且z无儿子(z指向的k2为要删除的结点,通过把k2的颜色变为红色然后删除,这样不会破坏红黑树的性质)

1.  z的兄弟结点为红色

    为了满足红黑树性质4,则其兄弟结点必有两个儿子且都为黑色。进行下面图中的调整

                                               

变换后,将k1涂成黑色,k2和A涂成红色,然后删除k2。

 

2.  z的兄弟结点为黑色且z的父结点为黑,且兄弟结点有两个儿子结点(为了满足红黑树的性质4,则兄弟结点的儿子必为红色)

                                                 

通过图中的变换后,其转化为1的情况。

3.  z的兄弟结点为黑且z的父结点为黑,兄弟结点有一个右儿子

                                               

直接删除k2的结点。

4. z的兄弟结点为黑且z的父结点为黑,兄弟结点有一个左儿子

                                        

通过图中的变换,变为情况3

5.  z的兄弟结点为黑且z的父结点为黑,兄弟结点无儿子,做法是:把z和z的兄弟结点涂成红色,z的父亲结点x为双黑色,然后删除z结点。接下来就是怎样把x的双黑去掉一层。此情况比较复杂,下面会做单独讨论的。

                                              

6.  z的父结点为红(则z兄弟结点必为黑)且z的兄弟结点有两个儿子(其儿子必为红色,可以分析红黑树的性质得到)

                                          

通过变换后,删除k2结点

7. z的父结点为红(则z兄弟结点必为黑)且z的兄弟结点有一个左儿子(其儿子必为红色,可以分析红黑树的性质得到)

                                       

变为情况8

8.  z的父结点为红(则z兄弟结点必为黑)且z的兄弟结点有一个右儿子(其儿子必为红色,可以分析红黑树的性质得到)

                                     

通过变换后,直接删除k2

9.  z的父结点为红(则z兄弟结点必为黑)且z的兄弟结点无儿子

                                   

通过变换后直接删除k2。

上面分析了删除的结点k2为左儿子的情况,当删除结点为右儿子可以类比的分析。下面给出上面情况5的分析:

对于删除结点k2、k2的父亲、k2的兄弟都为黑色,为了不破坏红黑树的性质,我们可以把k2、k2的兄弟涂成红色,把k2的父亲假设为双黑色,便可以把k2结点删除,这样并未破坏红黑树的性质。令x指向z的双黑父亲结点,下面的主要任务是把x指向的结点去掉一层黑色,怎么才能去掉一层黑色呢?分为下面几种情况

下面以x是左儿子为例说明。

1. x的兄弟结点为红色

      x为双黑色,为了满足红黑树性质4,x的兄弟结点后代必有黑色结点。

                                    

通过上面的变换后,其变为下述的情况2、3、4中的某一种,然后继续循环,知道满足红黑树的性质。

2.  x的兄弟结点为黑色,且兄弟结点有两个儿子也都是黑色的

                                                 

     第一种直接把双黑x指向的A结点去除一层黑色,同时没有破坏红黑树的性质,完成任务;第二种x指向的A结点去除一层黑色,但是B结点变为双黑的,x指针上移指向B结点,进入下次循环,把B结点的黑色去除一层。

3.  x的兄弟结点为黑色,且兄弟结点的左儿子为红色,右儿子为黑色(其中B的三角形表示该结点颜色可为黑、红任意一种)

                                                        

通过上面的变换,转化为情况4。进入下次循环。

4.  x的兄弟结点为黑色,右儿子为红色(其中B、C结点的三角形表示该结点可以为黑、红中任意一种颜色)

                                                   

通过上变化后,A结点的黑色去掉一层,因为在原始图中由A的父结点到A的两个儿子黑色结点数为2(因为A为双黑的),变换后由D到A的两个儿子黑色结点数也为2(此时A只是一层黑色)。

代码如下:

rb-tree.h

#pragma once#include<iostream>#include<string>using namespace std;template<typename Comparable>struct Node{Comparable element;//元素Node* left; //指向左儿子的左指针Node* right;//指向右儿子的右指针Node* parent; //指向父亲结点string color; //该结点的颜色Node(Comparable x,Node* l,Node* r,Node* p,string c):element(x),left(l),right(r),parent(p),color(c){}};enum MODE{PRE,MID,POST};template<typename Comparable>class rbtree{public:rbtree();rbtree(rbtree &rh);Comparable findmin();Comparable findmax();void insert(Comparable x);void remove(Comparable x);void print(MODE mode);private:Node<Comparable>* root;Node<Comparable>* findmin(Node<Comparable>* t);//寻找最小Node<Comparable>* findmax(Node<Comparable>* t);//寻找最大void insert(Node<Comparable>* &t);//插入Node<Comparable>* remove(Comparable x,Node<Comparable>* &t);//删除,其中t为要删除的结点void Lremove(Node<Comparable>* &x);void Rremove(Node<Comparable>* &x);void leftrotate(Node<Comparable>* t);//左旋void rightrotate(Node<Comparable>* t);//右旋void PrePrint(Node<Comparable>* t);void MidPrint(Node<Comparable>* t);void PostPrint(Node<Comparable>* t);};


 

rb-tree.cpp

#include "stdafx.h"#include"rb-tree.h"#include<iostream>#include<string>using namespace std;template<typename Comparable>rbtree<Comparable>::rbtree(){root=NULL;}template<typename Comparable>rbtree<Comparable>::rbtree(rbtree& rh){root=rh.root;}template<typename Comparable>Comparable rbtree<Comparable>::findmin(){return findmin(root)->element;}template<typename Comparable>Node<Comparable>* rbtree<Comparable>::findmin(Node<Comparable>* t){if(t==NULL)return NULL;else if(t->left==NULL)return t;elsefindmin(t->left);}template<typename Comparable>Comparable rbtree<Comparable>::findmax(){return findmax(root)->element;}template<typename Comparable>Node<Comparable>* rbtree<Comparable>::findmax(Node<Comparable>* t){if(t==NUUL)return NULL;else if(t->left==NULL)return t;elsefindmax(t->right);}template<typename Comparable>void rbtree<Comparable>::insert(Comparable x){Node<Comparable>* t=new Node<Comparable>(x,NULL,NULL,NULL,"RED");insert(t);}template<typename Comparable>void rbtree<Comparable>::insert(Node<Comparable>* &z)//插入{Node<Comparable>* x=root;Node<Comparable>* y=NULL;while(x!=NULL){y=x;if(z->element<x->element)x=x->left;elsex=x->right;}z->parent=y;if(y==NULL)root=z;else if(z->element<y->element)y->left=z;elsey->right=z;//调整红黑树,使其满足红黑树的性质bool flag=true;while(flag&&(z!=root)&&(z->parent->color=="RED"))//z的父结点是红色的且,z不是根结点{if(z->parent==z->parent->parent->left)//z的父亲结点是祖父的左儿子时{if(z->parent->parent->right==NULL)//如果其叔结点为空{if(z==z->parent->left){z->parent->color="BLACK";z->parent->parent->color="RED";rightrotate(z->parent->parent);flag=false;}else{z->color="BLACK";z->parent->parent->color="RED";leftrotate(z->parent);rightrotate(z->parent);flag=false;}}else{y=z->parent->parent->right;  //是z结点的叔结点if(y->color=="RED")          //case 1: z的叔结点是红色的{//cout<<"0"<<endl;z->parent->color="BLACK";y->color="BLACK";z->parent->parent->color="RED";z=z->parent->parent;   // z指针上移}else if(z==z->parent->right)  //case 2: z是右儿子{//cout<<"1"<<endl;z=z->parent;leftrotate(z);}else{//cout<<"2"<<endl; z->parent->color="BLACK";  //case 3: z->parent->parent->color="RED"; rightrotate(z->parent->parent);}}}else                           //z的父亲结点是祖父的右儿子{if(z->parent->parent->left==NULL)//叔结点为空{if(z==z->parent->right){z->parent->color="BLACK";z->parent->parent->color="RED";leftrotate(z->parent->parent);flag=false;}else{z->color="BLACK";z->parent->parent->color="RED";rightrotate(z->parent);leftrotate(z->parent);flag=false;}}else                 {y=z->parent->parent->left;//是z结点的叔结点if(y->color=="RED")          //case 1{//cout<<"3"<<endl;z->parent->color="BLACK";y->color="BLACK";z->parent->parent->color="RED";z=z->parent->parent;   // z指针上移}else if(z==z->parent->right) //case 2{//cout<<"4"<<endl;z->parent->color="BLACK";z->parent->parent->color="RED";leftrotate(z->parent->parent);}else   //case 3:{z=z->parent;   rightrotate(z);    }  }}}root->color="BLACK";}template<typename Comparable>void rbtree<Comparable>::remove(Comparable x){Node<Comparable>* z=remove(x,root);if(z->color=="RED")  //删除的结点为红色,则直接删除,不会破坏红黑树的性质{                   //因为删除的结点最多只有一个儿子结点,若删除结点为红色结点,则其必没有儿子结点。if(z==z->parent->left)z->parent->left=NULL;elsez->parent->right=NULL;delete z;}else            //删除结点为黑色,删除会破坏红黑树的性质     {if((z==root)||(z->left!=NULL)||(z->right!=NULL)) //z为根结点,(或者z有一个儿子,则该儿子必为红色的){Node<Comparable>* temp;if(z->left!=NULL){z->element=z->left->element;temp=z->left;z->left=NULL;delete temp;}else if(z->right!=NULL){z->element=z->right->element;temp=z->right;z->right=NULL;delete temp;}else   delete z;}else //z不为根结点,并且z无儿子结点{Node<Comparable>* temp=z;Node<Comparable>* w=NULL;  //记录z的兄弟结点,因为z结点为黑色,所以其必有兄弟结点。bool flag=true;            //标记是否把结点删除while(flag&&z!=root&&z->color=="BLACK")//并且若z有儿子也为红色的{if(z==z->parent->left)//z为左儿子结点时{w=z->parent->right;//z的右兄弟if(w->color=="RED")  //case1:z的兄弟为红色{w->color="BLACK";z->parent->color="RED";leftrotate(z->parent);w=z->parent->right;//左旋后,z的兄弟结点改变if(w->left==NULL&&w->right==NULL)//w无子结点,直接改变某些结点颜色,然后删除,{                                //否则进入下次循环z->color="RED";w->color="RED";z->parent->color="BLACK";z->parent->left=NULL;delete z;flag=false;}} else if(w->left!=NULL&&w->right!=NULL)//case 2:兄弟结点两个儿子都存在,则其必为红色 {if(z->parent->color=="BLACK")//父结点为黑色{w->left->color="BLACK";    w->right->color="BLACK";w->color="RED";         //进入下次循环,变成情况1}else                   //父结点为红色{   z->parent->color="BLACK";    z->color="RED";   w->right->color="BLACK";   w->color="RED";   leftrotate(z->parent);   z->parent->left=NULL;   delete z;   flag=false;} }    else if(w->left!=NULL)  //case 3:左儿子不为空,必为红色,右儿子为空{  w->color="RED";  w->left->color="BLACK";  rightrotate(w);   //进入下次循环,变成情况4}   else if(w->right!=NULL)//case 4:兄弟结点右儿子不为空,必为红色,左儿子为空{ z->color="RED"; if(z->parent->color=="BLACK")//父结点是黑色,要将z的右兄弟儿子变为黑色 w->right->color="BLACK";leftrotate(z->parent);z->parent->left=NULL;delete z;flag=false;}  else                //case 5:兄弟结点的两个儿子都为空{if(z->parent->color=="BLACK")//父结点为黑色        {Node<Comparable>* x=z->parent;z->color="RED";w->color="RED";x->left=NULL;delete z;if(x!=root){if(x==x->parent->left)Lremove(x);elseRremove(x);flag=false;}else{flag=false;}}else                     //父结点为红色{z->color="RED";w->color="RED";z->parent->color="BLACK";z->parent->left=NULL;delete z;flag=false;}}}else        //z为右儿子结点时{w=z->parent->left;//z的左兄弟结点if(w->color=="RED")          //case 1:{z->parent->color="RED";w->color="BLACK";rightrotate(z->parent);w=z->parent->left;if(w->left==NULL&&w->right==NULL){z->color="RED";w->color="RED";z->parent->color="BLACK";z->parent->right=NULL;delete z;flag=false;}}else if(w->left!=NULL&&w->right!=NULL)//case 2:{if(z->parent->color=="BLACK"){w->left->color="BLACK";w->right->color="BLACK";w->color="RED";}else{z->parent->color="BLACK";w->color="RED";z->color="RED";w->left->color="BLACK";rightrotate(z->parent);z->parent->right=NULL;delete z;flag=false;}}else if(w->left!=NULL)   //case 3:{z->color="RED";if(z->parent->color=="BLACK")//父结点是黑色w->left->color="BLACK";rightrotate(z->parent);z->parent->right=NULL;delete z;flag=false;}else if(w->right!=NULL)   //case 4:{w->color="RED";w->right->color="BLACK";leftrotate(w);}else                  //case 5:{if(z->parent->color=="BLACK"){Node<Comparable>* x=z->parent;z->color="RED";w->color="RED";x->right=NULL;delete z;if(x!=NULL){if(x==x->parent->left)Lremove(x);elseRremove(x);flag=false;}else{flag=false;}}else{w->color="RED";z->color="RED";z->parent->color="BLACK";z->parent->right=NULL;delete z;flag=false;}}}  }}}}template<typename Comparable>Node<Comparable>* rbtree<Comparable>::remove(Comparable x,Node<Comparable>* &t)//返回要删除的结点的指针{if(t==NULL)return NULL;else if(x<t->element)remove(x,t->left);else if(x>t->element)remove(x,t->right);else if(t->left!=NULL&&t->right!=NULL)//删除结点左右指针都不是空,返回右侧中最小的元素指针{Node<Comparable>* temp=findmin(t->right);t->element=temp->element;return temp;}else    //左右指针都为空或只有一个为空。return t;}template<typename Comparable>void rbtree<Comparable>::Lremove(Node<Comparable>* &x)//父结点是黑色且是左儿子,且兄弟结点无儿子的删除{bool flag=true;Node<Comparable>* w=x->parent->right;//兄弟结点while(flag&&x!=root){if(w->color=="RED")//case 1:兄弟结点为红色{x->parent->color="RED";w->color="BLACK";leftrotate(x->parent);w=x->parent->right;}else if(w->left->color=="BLACK"&&w->right->color=="BLACK")//case 2:兄弟结点为黑色,{                                                         //且兄弟结点两个儿子为黑色if(x->parent->color=="RED")//父结点为红色{x->parent->color="BLACK";w->color="RED";flag=false;}else                  //父结点为黑色{if(x->parent==root){w->color="RED";flag=false;}else{w->color="RED";x=x->parent;   //此时x指针指向父结点,表明父结点变为双黑w=x->parent->right;}}}else if(w->right->color=="RED")  //case 3:兄弟结点右儿子是红色,左儿子是任意{w->color=x->parent->color;x->parent->color="BLACK";w->right->color="BLACK";leftrotate(x->parent);flag=false;}else                    //case 4:兄弟结点左儿子是红色,右儿子是黑色{w->color="RED";w->left->color="BLACK";rightrotate(w);              //变成情况3w=x->parent->right;}}                                                             }template<typename Comparable>void rbtree<Comparable>::Rremove(Node<Comparable>* &x)//父结点是黑色且是右儿子,且兄弟结点无儿子的删除{bool flag=true;Node<Comparable>* w=x->parent->left;while(flag&&x!=root){if(w->color=="RED")//case 1:兄弟结点为红{x->parent->color="RED";w->color="BLACK";rightrotate(x->parent);w=x->parent->left;}else if(w->left->color=="BLACK"&&w->right->color=="BLACK")//case 2:兄弟结点两个儿子为黑{if(x->parent->color=="RED"){w->color="RED";x->parent->color="BLACK";flag=false;}else{if(x->parent==root){w->color="RED";flag=false;}else{w->color="RED";x=x->parent;w=x->parent->left;}}}else if(w->left->color=="RED") //case 3:兄弟结点左儿子为红,右儿子为任意{w->color=x->parent->color;x->parent->color="BLACK";w->left->color="BLACK";rightrotate(x->parent);flag=false;}else   //case 4:右儿子为红,左儿子为黑。变化后变为{w->color="RED";w->right->color="BLACK";leftrotate(w);w=x->parent->left;}}}template<typename Comparable>void rbtree<Comparable>::print(MODE mode){if(mode==PRE)PrePrint(root);else if(mode==MID)MidPrint(root);else if(mode==POST)PostPrint(root);elsereturn;cout<<endl;}template<typename Comparable>void rbtree<Comparable>::PrePrint(Node<Comparable>* t){if(t==NULL)return;else{cout<<"("<<t->element<<","<<t->color<<")"<<" ";PrePrint(t->left);PrePrint(t->right);}}template<typename Comparable>void rbtree<Comparable>::MidPrint(Node<Comparable>* t){if(t==NULL)return;else{MidPrint(t->left);cout<<"("<<t->element<<","<<t->color<<")"<<" ";MidPrint(t->right);}}template<typename Comparable>void rbtree<Comparable>::PostPrint(Node<Comparable>* t){if(t==NULL)return;else{PostPrint(t->left);PostPrint(t->right);   cout<<"("<<t->element<<","<<t->color<<")"<<" ";}}template<typename Comparable>void rbtree<Comparable>::leftrotate(Node<Comparable>* t)//左旋{Node<Comparable>* temp=t->right;t->right=temp->left;temp->left=t;if(t!=root){temp->parent=t->parent;if(t==t->parent->left)t->parent->left=temp;elset->parent->right=temp;}elseroot=temp;t->parent=temp;if(t->right!=NULL)t->right->parent=t;}template<typename Comparable>void rbtree<Comparable>::rightrotate(Node<Comparable>* t) //右旋{Node<Comparable>* temp=t->left;t->left=temp->right;temp->right=t;if(t!=root){temp->parent=t->parent;if(t==t->parent->right)t->parent->right=temp;elset->parent->left=temp;}elseroot=temp;t->parent=temp;if(t->left!=NULL)t->left->parent=t;}


RB_Tree.cpp

// RB_Tree.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include"rb-tree.h"#include"rb-tree.cpp"#include<iostream>#include<string>using namespace std;int _tmain(int argc, _TCHAR* argv[]){rbtree<int> r;int a[9]={18,10,20,9,15,19,21,14,16};for(int i=0;i<9;i++)r.insert(a[i]);r.remove(21);r.print(MID);return 0;}


 

原创粉丝点击