红黑树
来源:互联网 发布:js判断偶数 编辑:程序博客网 时间:2024/06/15 08:25
红黑树是许多“平衡”搜索树的一种,可以保证在最坏情况下基本动态集合操作的时间复杂度为O(lgn)。
红黑树的性质
红黑树是一棵二叉搜索树,它在每个结点上增加了一个存储位来表示结点的颜色,可以是RED和BLACK。
通过对各个结点的颜色进行约束,红黑树确保没有一条路径会比其它路径长出两倍,因此是近似于平衡的。
一个红黑树是满足下面红黑性质的二叉搜索树:
1.每个结点或是红色的,或是黑色的
2.根节点是黑色的
3.每个叶结点(NIL)是黑色的
4.如果一个结点是红色的,则它的两个子结点都是黑色的
5.对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点
下面是一棵红黑树的例子
为了便于处理红黑树代码的边界条件,使用一个哨兵来代表NIL。
旋转
搜索树操作TREE-INSERT和TREE-DELETE会对树做修改,结果可能违反了红黑性质。为了维护这些性质,必须改变树中某些结点的颜色以及指针结构。
指针结构的修改是通过旋转来完成的,下面给出了两种旋转:左旋和右旋
下面是LEFT-ROTATE的伪代码,假设x.right≠T.nil且根结点的父结点为T.nil。
1 LEFT-ROTATE(T,x) 2 y=x.right //set y 3 x.right=y.left //trun y's left subtree into x'right subtree 4 if y.left≠T.nil 5 y.left.p=x 6 y.p=x.p //link x' parent to y 7 if x.p==T.nil 8 T.root=y 9 else if x==x.p.left10 x.p.left=y11 else x.p.right=y12 y.left=x //put x on y'left13 x.p=y
下面是LEFT-ROTATE操作修改二叉搜索树的例子。
RIGHT-ROTATE操作的代码是对称的。
1 RIGHT-ROTATE(T,y) 2 x=y.left //set x 3 y.left=x.right //turn x's right subtree into y's right subtree 4 if x.right≠T.nil 5 x.right.p=y 6 x.p=y.p //link y's parent to x 7 if y.p==T.nil 8 T.root=x 9 else if y==y.p.left10 y.p.left=x11 else y.p.right=x12 x.right=y //put y on x's left13 y.p=x
插入
我们需要对二叉平衡树的插入过程略作修改。我们需要一个辅助程序RB-INSERT-FIXUP来对结点重新着色并选择。
1 RB-INSERT(T,z) 2 y=T.nil 3 x=T.root 4 while x≠T.nil 5 y=x 6 if z.key<x.key 7 x=x.left 8 else 9 x=x.right10 z.p=y11 if y==T.nil12 T.root=z13 else y.right=z14 z.left=T.nil15 z.right=T.nil16 z.color=RED17 RB-INSERT-FIXUP(T,z)
TREE-INSERT和RB-INSERT之间有4处不同:
1.TREE-INSERT内所有的NIL都被T.nil代替
2.RB-INSERT将z.left和z.right置为T.nil
3.将z着为红色
4.因为z着为红色可能违反红黑性质,所有调用RB-INSERT-FIXUP(T,z)来保持红黑性质。
1 RB-INSERT-FIXUP(T,z) 2 while z.p.color==RED 3 if z.p==z.p.p.left 4 y=z.p.p.right 5 if y.color==RED //case 1 6 z.p.color=BALCK 7 y.color=BALCK 8 y.p.p.color=RED 9 z=z.p.p10 else 11 if z==z.p.right //case 212 z=z.p13 LEFT-ROTATE(T,z)14 else15 z.p.color=BALCK //case 316 z.p.p.color=RED17 RIGHT-ROTATE(T,z.p.p)18 else(same as then clause with "right" and "left" exchanged)19 T.root.color=BALCK
下面给出一个范例,显示在一棵红黑树上RB-INSERT-FIXUP如何操作
RB-INSERT-FIXUP(T,z)过程一直把z迭代向上,直到z结点的父结点为黑色,每次有3种情况:
(a)判断z的叔结点,如果为红色,应用case 1。
(b)如果z的叔结点为黑色,而且z是的父结点的右孩子,应用case 2
(c)如果z的叔结点为黑色,而且z是的父结点的左孩子,应用case 3
删除
修改二叉平衡树中TREE-DELETE调用的子过程TRANSPLANT,并将其应用到红黑树上。
RB-TRANSPLANT用一棵以v为根的子树来替换一棵以u为根的子树:结点u的双亲就变为结点v的双亲,并且最后v成为u的双亲的相应孩子
1 RB-TRANSPLANT(T,u,v)2 if u.p==T.nil3 T.root=v4 else if u==u.p.left5 u.p.left=v6 else u.p.right=v7 v.p=u.p
过程RB-DELETE与TREE-DELETE类似,只是多了几行伪代码用来记录结点y的踪迹,y有可能导致红黑性质的破坏。
1.当要删除结点z,且此时z有少于两个子结点时,z从树中删除,并将这个孩子(可能为T.nil)提升到树中z的位置上。
2.当z有两个子结点时,y应该是z的后继,并且y将移至树中的z位置。
(a)如果y是z的右孩子,那么用y替换z,原来z的左孩子称为y的左孩子(可以证明原来y的左孩子必为T.nil)。
(b)如果y并不是z的右孩子。则先用y的右孩子替换y,然后用y替换z
如果z的子结点少于两个时,使用y记录z的颜色,x用来记录z的左或右结点。
如果z的子结点数目为两个的时候,y用来记录替换z的结点,x用来记录y的右结点。
1 RB-DELETE(T,z) 2 y=z 3 y-original-color=y.color 4 //只有一个子结点 5 if z.left==T.nil 6 x=z.right 7 RB-TRANSPLANT(T,z,z.right) 8 else if z.right==T.nil 9 x=z.left10 RB-TRANSPLANT(T,z,z.left)11 //有两个子结点12 else y=TREE-MINIMUM(z.right)13 y-original-color=y.color14 x=y.right15 if y.p==z16 x.p=y17 else RB-TRANSPLANT(T,y,y.right)18 y.right=z.right19 y.right.p=y20 RB-TRANSPLANT(T,z,y)21 y.left=z.left22 y.left.p=y23 y.color=z.color24 if y.original-color==BALCK25 RB-DELETE-FIXUP(T,x)
删除结点z之后,如果y.original-color==BALCK,RB-DELETE调用一个辅助过程RB-DELETE-FIXUP,该过程通过改变颜色和执行旋转来恢复红黑性质
1 while x≠T.root and x.color==BALCK 2 if x==x.p.left 3 w=x.p.right 4 if w.color=RED //case 1 5 w.color=BALCK 6 x.p.color=RED 7 LEFT-ROTATE(T,x.p) 8 w=x.p.right 9 if w.left.color==BALCK and w.right.color==BALCK //case 210 w.color=RED11 x=x.p12 else13 if w.right.color=BALCK //case 314 w.left.color=BALCK15 w.color=RED16 RIGHT-ROTATE(T,w)17 w=x.p.right18 else //case 419 w.color=x.p.color20 x.p.color=BALCK21 w.right.color=BALCK22 LEFT-ROTATE(T,x.p)23 x=T.root24 else (same as then clause with "right" and "left" exchanged)25 x.color=BLACK
下面给出代码中的4种情况
1.x的兄弟结点w是红色的
2.x的兄弟结点w是黑色的,而且w的两个子结点都是黑色的
3.x的兄弟结点w是黑色的,w的左孩子是红色的,w的右孩子是黑色的
4.x的兄弟结点w是黑色的,且w的右孩子是红色的
实现和测试代码
因为红黑色应用比较广,所有决定把它的操作封装成一个类。跟伪代码有一点不同的是:没有设置哨兵nil,很多函数都加上判断是否为NULL。
没有处理查找不到跟删除没有的元素的代码。
1 #define RED 0 2 #define BLACK 1 3 4 #include <stdbool.h> 5 #include <iostream> 6 using namespace std; 7 8 9 struct node 10 { 11 int key; 12 int data; 13 bool color; 14 node *left; 15 node *right; 16 node *parent; 17 }; 18 19 class RBTree 20 { 21 private: 22 node *root; 23 //左旋 24 void left_rotate(node *x) 25 { 26 node *y=x->right; 27 x->right=y->left; 28 if(y->left!=NULL) 29 y->left->parent=x; 30 y->parent=x->parent; 31 if(x->parent==NULL) 32 root=y; 33 else if(x==x->parent->left) 34 x->parent->left=y; 35 else 36 x->parent->right=y; 37 y->left=x; 38 x->parent=y; 39 } 40 //右旋 41 void right_rotate(node *y) 42 { 43 node *x=y->left; 44 y->left=y->right; 45 if(x->right!=NULL) 46 x->right->parent=y; 47 x->parent=y->parent; 48 if(y->parent==NULL) 49 root=x; 50 else if(y==y->parent->left) 51 y->parent->left=x; 52 else 53 y->parent->right=x; 54 x->right=y; 55 y->parent=x; 56 } 57 //找出根结点为t的子树的最小键的结点 58 node *tree_minimum(node *t) 59 { 60 while(t->left!=NULL) 61 t=t->left; 62 return t; 63 } 64 //对插入之后进行修正,保持红黑性质 65 void rb_insert_fixup(node *z) 66 { 67 //当z不是根同时父结点的颜色是red 68 while(root!=z&&z->parent->color==RED) 69 { 70 //如果z结点的父结点是其父结点的左孩子(如果是右孩子则执行else) 71 if(z->parent==z->parent->parent->left) 72 { 73 //叔结点 74 node *y=z->parent->parent->right; 75 //如果叔结点不为NULL并且颜色为RED 76 if(y!=NULL&&y->color==RED) 77 { 78 z->parent->color=BLACK; 79 y->color=BLACK; 80 z->parent->parent->color=RED; 81 z=z->parent->parent; 82 } 83 //否则执行else 84 else 85 { 86 //如果该结点是其父结点的右孩子 87 if(z==z->parent->right) 88 { 89 z=z->parent; 90 left_rotate(z); 91 } 92 //如果该结点是其父结点的左孩子 93 else 94 { 95 z->parent->color=BLACK; 96 z->parent->parent->color=RED; 97 right_rotate(z->parent->parent); 98 } 99 } 100 }101 else102 {103 node *y=z->parent->parent->left;104 if(y!=NULL&&y->color==RED)105 {106 z->parent->color=BLACK;107 y->color=BLACK;108 z->parent->parent->color=RED;109 z=z->parent->parent;110 }111 else 112 {113 if(z==z->parent->left)114 {115 z=z->parent;116 right_rotate(z);117 }118 else119 {120 z->parent->color=BLACK;121 z->parent->parent->color=RED;122 left_rotate(z->parent->parent);123 }124 } 125 }126 }127 root->color=BLACK;128 }129 //中序遍历 130 void tree_inorder_p(node *t)131 {132 if(t!=NULL)133 {134 tree_inorder_p(t->left);135 cout<<"key:"<<t->key<<" data:"<<t->data<<" color:"<<(t->color?"BLACK":"RED")<<endl;136 tree_inorder_p(t->right);137 }138 } 139 //删除结点调用的子过程 用来将一棵以v为根的子树来替换一棵以u为根的子树 140 void rb_transplant(node *u,node *v) 141 {142 //u为根结点 143 if(u->parent==NULL)144 root=v;145 //判断u是其父结点的左孩子还是右孩子 146 else if(u==u->parent->left)147 u->parent->left=v;148 else 149 u->parent->right=v;150 if(v!=NULL) 151 v->parent=u->parent; 152 } 153 //删除结点之后的修正函数 用来保持红黑性质 154 void rb_delete_fixup(node *x)155 {156 node *w;157 while(x!=root&&(x==NULL||x->color==BLACK))158 {159 //如果x是其父结点的左孩子 160 if(x==x->parent->left)161 {162 w=x->parent->right;163 if(w->color==RED)164 {165 w->color=BLACK;166 x->parent->color=RED;167 left_rotate(x->parent);168 w=x->parent->right;169 }170 if((w->left==NULL||w->left->color==BLACK)&&171 (w->right==NULL||w->right->color==BLACK))172 {173 w->color=RED;174 x=x->parent;175 } 176 else177 {178 if((w->right==NULL||w->right->color==BLACK))179 {180 if(w->left!=NULL)181 w->left->color=BLACK;182 w->color=RED;183 right_rotate(w);184 w=x->parent->right;185 }186 w->color=x->parent->color;187 x->parent->color=BLACK;188 if(w->right!=NULL)189 w->right->color=BLACK;190 left_rotate(x->parent);191 x=root;192 }193 }194 else195 {196 w=x->parent->left;197 if(w->color==RED)198 {199 w->color=BLACK;200 x->parent->color=RED;201 right_rotate(x->parent);202 w=x->parent->left;203 }204 if((w->left==NULL||w->left->color==BLACK)&&205 (w->right==NULL||w->right->color==BLACK))206 {207 w->color=RED;208 x=x->parent;209 } 210 else211 {212 if((w->left==NULL||w->left->color==BLACK))213 {214 if(w->right!=NULL)215 w->right->color=BLACK;216 w->color=RED;217 left_rotate(w);218 w=x->parent->right;219 }220 w->color=x->parent->color;221 x->parent->color=BLACK;222 if(w->left!=NULL)223 w->left->color=BLACK;224 left_rotate(x->parent);225 x=root;226 }227 } 228 }229 x->color=BLACK;230 } 231 void delete_tree(node *t)232 {233 if(t!=NULL)234 {235 delete_tree(t->left);236 delete t;237 delete_tree(t->right);238 }239 }240 241 public:242 RBTree(node *r) {root=r;root->color=BLACK;}243 //插入函数 244 void tree_insert(node* z)245 {246 //x是当前结点,y用来记录插入位置的父结点 247 node *y=NULL;248 node *x=root;249 //找到插入结点的父结点,并用y记录起来 250 while(x!=NULL)251 {252 y=x;253 if(z->key<x->key)254 x=x->left;255 else256 x=x->right;257 }258 //插入结点 259 z->parent=y;260 if(y==NULL)261 root=z;262 else if(z->key<y->key)263 y->left=z;264 else265 y->right=z;266 z->right=NULL;267 z->left=NULL;268 z->color=RED;269 rb_insert_fixup(z);270 } 271 //根据键值来make_node 272 static node *make_node(int k,int d)273 {274 node *z=new node();275 z->key=k;276 z->data=d;277 z->color=RED;278 z->left=NULL;279 z->right=NULL;280 z->parent=NULL;281 return z;282 }283 //中序遍历包装函数 284 void tree_inorder(){tree_inorder_p(root);}285 //查找函数 286 node *tree_search(int key)287 {288 node *t=root;289 while(t!=NULL&&key!=t->key)290 {291 if(key<t->key)292 t=t->left;293 else294 t=t->right;295 }296 return t;297 }298 //删除函数299 void rb_delete(node *z)300 {301 node *y=z;302 node *x;303 int y_original_color=y->color;304 if(z->left==NULL)305 {306 x=z->left;307 rb_transplant(z,z->left);308 }309 else if(z->right==NULL)310 {311 x=z->left;312 rb_transplant(z,z->left);313 }314 else315 {316 y=tree_minimum(z->right);317 y_original_color=y->color;318 x=y->right;319 if(y->parent==z)320 x->parent=y;321 else322 {323 rb_transplant(y,y->right);324 y->right=z->right;325 y->right->parent=y;326 } 327 rb_transplant(z,y);328 y->left=z->left;329 y->left->parent=y;330 y->color=z->color;331 }332 if(y_original_color==BLACK)333 rb_delete_fixup(x);334 delete z;335 } 336 //析构函数 337 ~RBTree()338 {339 delete_tree(root);340 }341 };
测试代码
1 #include <stdbool.h> 2 #include <iostream> 3 #include <time.h> 4 #include <stdlib.h> 5 using namespace std; 6 7 int main() 8 { 9 srand(time(NULL));10 RBTree *t=new RBTree(RBTree::make_node(1,20));11 12 node *n1=RBTree::make_node(2,rand()%100);13 node *n2=RBTree::make_node(3,rand()%100);14 node *n3=RBTree::make_node(4,rand()%100);15 node *n4=RBTree::make_node(5,rand()%100);16 t->tree_insert(n1); 17 t->tree_insert(n2); 18 t->tree_insert(n3); 19 t->tree_insert(n4); 20 21 cout<<"after insert:"<<endl;22 t->tree_inorder();23 t->rb_delete(n2);24 cout<<endl;25 cout<<"after delete:"<<endl;26 t->tree_inorder();27 cout<<endl;28 29 cout<<"serach key=2 data="<<t->tree_search(2)->data<<endl;30 delete t;31 return 0;32 }