红黑树
来源:互联网 发布:php字符串分割成数组 编辑:程序博客网 时间:2024/06/16 06:47
红黑树:
enum nodecolor {red,black};struct red_black_node{ int key; red_black_node *left; red_black_node *right; red_black_node *p; nodecolor color; red_black_node(int a,nodecolor c=red) { key=a; color=c; }};static red_black_node *NIL=new red_black_node(0,black);red_black_node* tree_minimum(red_black_node *x){ while(x->left!=NIL) x=x->left; return x;}red_black_node* tree_successor(red_black_node *x)//寻找后继结点,没有则返回NIL,O(h){ if(x->right!=NIL)//如果x的右子树非空,后继即右子树的最左结点 return tree_minimum(x->right); red_black_node* y=x->p; //如果x的右子树为空,向上查找,直到遇到某个是其父结点的左儿子的结点为止 while(y!=NIL && x==y->right) { x=y; y=y->p; } return y;}red_black_node* left_rotate(red_black_node *t,red_black_node *x)//左旋,根为t,旋转结点为x,y为x的右儿子,返回旋转之后的根,O(1){ red_black_node *root=t; red_black_node *y=x->right; x->right=y->left; if(y->left!=NIL) y->left->p=x; y->p=x->p; if(x->p==NIL)//x是根的情况 root=y; else if(x==x->p->left) x->p->left=y; else x->p->right=y; y->left=x; x->p=y; return root;}red_black_node* right_rotate(red_black_node *t,red_black_node *x)//右旋,根为t,旋转结点为x,y为x的左儿子,返回旋转之后的根,O(1){ red_black_node *root=t; red_black_node *y=x->left; x->left=y->right; if(y->right!=NIL) y->right->p=x; y->p=x->p; if(x->p==NIL)//x是根的情况 root=y; else if(x==x->p->left) x->p->left=y; else x->p->right=y; y->right=x; x->p=y; return root;}red_black_node* rb_insert_fixup(red_black_node *x,red_black_node *z)//在插入z后,调用该函数来保持红黑性质,x为根,z为插入的结点,返回根结点,O(lgn),最多旋转2次{ red_black_node *y; while(z->p->color==red)//z和z的父结点都为红色时才需要调整 { if(z->p==z->p->p->left) { y=z->p->p->right;//y是z的叔叔结点,根据y的颜色分成3种情况 if(y->color==red)//情况1,y为红色 { z->p->color=black; y->color=black;//将父结点和叔叔结点都着黑色以解决z和z的父结点都为红色 z->p->p->color=red;//将祖父结点着红色以保持性质5 z=z->p->p;//将z的祖父的父结点可能也是红色,将z置为其祖父再次循环 } else//情况2和3,y为黑色 { if(z->p->right==z)//情况2,y黑色且z是右孩子 { z=z->p; x=left_rotate(x,z);//对z父亲使用一次左旋使之转变为情况3 } //情况3,y黑色且z是左孩子 z->p->color=black; z->p->p->color=red; right_rotate(x,z->p->p);//此时z的父结点为黑色,无需再执行while循环 } } else//下面的跟上面一样,只要左右互换 { y=z->p->p->left; if(y->color==red) { z->p->color=black; y->color=black; z->p->p->color=red; z=z->p->p; } else { if(z->p->left==z) { z=z->p; x=right_rotate(x,z); } z->p->color=black; z->p->p->color=red; left_rotate(x,z->p->p); } } } x->color=black;//最后记得把根着为黑色 return x;}red_black_node* rb_insert(red_black_node *x,red_black_node *z)//在根为x的红黑树中插入结点z,O(lgn),最多旋转2次{ red_black_node *y=NIL; red_black_node *root=x; while(x!=NIL) { y=x; if(z->key<x->key) x=x->left; else x=x->right; } z->p=y; if(y==NIL) root=z; else if(z->key<y->key) y->left=z; else y->right=z; z->left=NIL; z->right=NIL; z->color=red;//要将z的孩子置为NIL并着为红色 x=root; x=rb_insert_fixup(x,z);//保持红黑性质 return x;}red_black_node* rb_delete_fixup(red_black_node *x,red_black_node *q)//删除黑色结点后恢复红黑性质,x为根,q为删除结点y的唯一孩子或者为NIL,返回根结点,O(lgn),最多旋转3次{ red_black_node* w=NIL; while(q!=x && q->color==black) //while循环的目标是将额外的黑色沿树上移 { if(q==q->p->left) { w=q->p->right;//w是q的兄弟,q为双重黑色,所以w不可能为NIL if(w->color==red)//情况1,w是红色 { w->color=black; q->p->color=red;//改变w和q->p的颜色 x=left_rotate(x,q->p);//对q->p进行左旋,红黑性质继续保持 w=q->p->right;//w赋值为q的新兄弟,转到情况2,3,4 } if(w->left->color==black && w->right->color==black) //情况2,w是黑色且w两个孩子都是黑色 { w->color=red; q=q->p; //通过while循环不断上升,如遇到红色结点跳出循环,在函数最后q被着黑色 //如果是通过情况1进入情况2,则q->p必为红色,直接循环结束 } else//情况3,4 { if(w->right->color==black) //情况3,w是黑色且w的孩子左红右黑 { w->left->color=black; w->color=red; x=right_rotate(x,w); w=q->p->right; //交换w和其左孩子颜色并对w右旋,转情况4 } //情况4,w是黑色且右孩子是红色 w->color=q->p->color; q->p->color=black; w->right->color=black; x=left_rotate(x,q->p); //去掉q额外的黑色 q=x;//q置为根,循环结束 } } else { w=q->p->left; if(w->color==red) { w->color=black; q->p->color=red; x=right_rotate(x,q->p); w=q->p->left; } if(w->left->color==black && w->right->color==black) { w->color=red; q=q->p; } else if(w->left->color==black) { w->right->color=black; w->color=red; x=left_rotate(x,w); w=q->p->left; } w->color=q->p->color; q->p->color=black; w->left->color=black; x=right_rotate(x,q->p); q=x; } } q->color=black; return x;}red_black_node* rb_delete(red_black_node *x,red_black_node *z)//在根为x的红黑树中删除结点z,O(lgn),最多旋转3次{ red_black_node *y=NIL; red_black_node *q=NIL; red_black_node *root=x; if(z->left==NIL||z->right==NIL) y=z; else y=tree_successor(z); if (y->left!=NIL) q=y->left; else q=y->right; q->p=y->p;//无条件赋值 if(y->p==NIL) root=q; else if(y==y->p->left) y->p->left=q; else y->p->right=q; if(y!=z) z->key=y->key; x=root; if(y->color==black)//删除的是黑色结点才调用 x=rb_delete_fixup(x,q);//q是y的唯一孩子或者是哨兵NIL return x;}void inorder_walk(red_black_node *x){ if(x!=NIL) { inorder_walk(x->left); if(x->color==red) cout<<"red"; else cout<<"black"; cout<<x->key<<" "; inorder_walk(x->right); }}
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 05 Concurrency and Race Conditions .
- rdesktop用法
- 数据库系统日志的处理和作用
- 如何实现简单五子棋?
- linux shell 字符串操作(长度,查找,替换)详解
- 红黑树
- Js_数据类型综合练习
- Java单例设计模式,多线程下同步
- 用户登录验证完整版
- 传智播客——毕向东25--第8天总结-7
- 外观模式(Façade Pattern)
- 如何编程判断构件相交?
- Linux环境进程间通信(一):管道及有名管道
- Redhat EN 6.0下安装项目管理软件redmine