rbtree插入算法分析
#include<iostream> #include<queue> using namespace std; struct rbnode{ int key; int color;//1=black,0=red; struct rbnode *p,*left,*right; rbnode(){} rbnode(int k){key=k; } }; rbnode *nil; bool RBinsert(rbnode **root,int k); void LevelOrder(rbnode *t); void RBinserFix(rbnode **root,rbnode *z); void Left(rbnode **root, rbnode *x); void Right(rbnode **root, rbnode *x); void Left(rbnode **root, rbnode *x){ if(x->right!=nil){ rbnode * y=nil; y=x->right; x->right=y->left; if(y->left!=nil)y->left->p=x; y->p=x->p; if(x->p==nil) (*root)=y; else if(x==x->p->left) x->p->left=y; else x->p->right=y; y->left=x; x->p=y;} } void Right(rbnode **root, rbnode *x){ if(x->left!=nil){ rbnode * y=nil; y=x->left; x->left=y->right; if(y->right!=nil)y->right->p=x; y->p=x->p; if(x->p==nil) (*root)=y; else if(x==x->p->right) x->p->right=y; else x->p->left=y; y->right=x; x->p=y; } } void RBinserFix(rbnode **root,rbnode *z){ rbnode* y=nil; while(z!=*root&&z->p->color==0){ if(z->p==z->p->p->left){ y=z->p->p->right; if(y->color==0){ z->p->color=1; y->color=1; z->p->p->color=0; z=z->p->p; }else { if(z==z->p->right){z=z->p;//LEFT Left(root,z);} z->p->color=1; z->p->p->color=0; //RightRotate(); Right((root),z->p->p); } }else { y=z->p->p->left; if(y->color==0){ z->p->color=1; y->color=1; z->p->p->color=0; z=z->p->p; }else { if(z==z->p->left){z=z->p;//LEFT Right(root,z); } z->p->color=1; z->p->p->color=0; //RightRotate(); Left((root),z->p->p);} } } (*root)->color=1; } bool RBinsert(rbnode **root,int k){ rbnode* z=new rbnode(k); //cout<<root->color; rbnode* y=nil; rbnode* x=*root; while(x!=nil){ y=x; if(k==x->key)return 0; if(k<x->key)x=x->left; else x=x->right; } z->p=y; if(y==nil) {(*root)=z;(*root)->p=nil;} else if(k<y->key) y->left=z; else y->right=z; z->left=nil;z->right=nil; z->color=0; //LevelOrder(*root); RBinserFix(root,z); return 1; } void Visit(rbnode *t) { if (t) { cout << t->key; if(t->color)cout<<"黑 "; else cout<<"红 "; } } void LevelOrder(rbnode *t) {// 对* t逐层遍历 queue<rbnode*> Q; while (t!=nil) { Visit(t); if (t->left!=nil) Q.push(t->left); if (t->right!=nil) Q.push(t->right); if (Q.empty()) break; t=Q.front(); Q.pop(); } } void main(){ //rbnode* root= //root->color=1;//1=black //root->p=nil; //root->left=nil;root->right=nil; rbnode** root=(rbnode**)malloc(sizeof(rbnode*));; nil=new rbnode(); nil->color=1; *root =nil; //rbnode cout<<"输入操作类型:1插入元素 2输出结构 3删除节点 4退出"<<endl; int sinin,num; cin>>sinin; while(sinin!=4) {switch(sinin){ case 1: cout<<"插入: "; cin>>num; if(!RBinsert(root,num))cout<<"插入重复值"<<endl; // cout<<" root --key:"<<(*root)->p->color<<endl; break; case 2: LevelOrder(*root); cout<<endl; break; case 3: break; }cout<<"输入操作类型:1插入元素 2输出结构 3删除节点 4退出"<<endl; cin>>sinin; } }
红黑树每个节点由5个域组成:parent,leftchild,rightchild,key,color组成
插入过程分为两大部分,即1)插入到树中2)维持红黑树性质
1)根据节点key值,插入时P节点的左子树均小于该节点key值,右子树各节点均大于p节点的key值,根据这个特征,如果小于p的key就到p的左子树寻找,否则到p的右子树。
2)在插入一个节点到树中后,会引起不满足红黑树定义的变化,需要进行调节。调节方法有三种:1、调节颜色,2、左旋,3、右旋。不满足红黑树条件的原因是,插入时父节点为红色(或为根)。下图展示针对各种情况的旋转调节方法:
注:调节时先采用调节颜色的方法,且最对经过2次旋转达到平衡。
旋转过程中,二叉搜索树的性质保持不变
插入过程:小于节点值访问左子树,大于节点值访问右子树,否则返回插入失败O(logn)
调节过程:
void RBinserFix(T, z){
while(colorp[z] ==RED){
//若z为根,则p[z]=nil[T],颜色为黑,不进入循环,p[z]为黑也不进入
if(p[z] == left[p[p[z]]]){//z的父节点是祖父节点的左孩子
y= right[p[p[z]]];//y是z的叔叔,若为红色则调节颜色
if(color[y] ==RED){//改变颜色,case1
color[p[z]] =BLACK;
color[y]=BLACK;
color[p[p[z]]=RED;
z=p[p[z]];
}else //case2,3
{ if(z==right[p[z]]){//case 2,左旋
z=p[z]; Left(root,z);
}
Color[p[z]]=BLACK;//case3,右旋
Color[p[p[z]]]=RED;
Right((root),p[p[z]]);//p[z]为黑,退出
}
}else {//对调上方“左”“右”, z的父节点是祖父节点的右孩子}
}//endwhile
Color[root[t]]=BLACK;
}
复杂程度为O(logn)
Left(T,x)
{//假设right[x]!=nil[T]
Y=right[x] //记录指向y节点的指针,1
right[x]=left[y];p[left[y]]=x;// B连到X右,2
p[y]=p[x ];//修改parent指针,3
if(p[x]=nil[T]) //x是根
root[T]=y; //修改树指针
else if (x==left[p[x]]) left[p[x]]=y; //修改父节点孩子指针
else right[p[x]]=y;
left[y]=x; p[x]=y;//x连接到y,4
}
复杂程度为O(1)
整个插入算法的时间是O(logn)