红黑树
来源:互联网 发布: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;}
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- HDU 4318 Power transmission
- vector中的erase方法跟algorithm的remove
- hdu4734之数位dp
- 常用的字符串处理函数
- 手机风波(二)の惊喜篇
- 红黑树
- 十万行代码
- recv send 阻塞和非阻塞
- [每日一题] 11gOCP 1z0-052 :2013-09-18 理解EXPDP/IMPDP.......................................B36
- 邻接表--创建图、删除图、深度优先搜索、广度优先搜索---代码
- Solr4.3+zookeeper+tomcat 集群部署高可用
- Backbone.js系列一 - Backbone.js初探
- 消息队列(message queue)
- Facebook总照片数达2500亿 日均上传3亿5000万张