一、概念
红黑树是一棵二叉搜索树,它在每个结点上增加了一个存储位来表示结点的颜色,可以是RED或BLACK。通过对任何一条从根到叶子的简单路径上各个结点的颜色进行约束,红黑树确保没有一条路径会比其他路径长2倍,因而是近似于平衡的。
二、定义
一棵红黑树是满足下面红黑性质的二叉搜索树:
1、每个结点或是红色,或是黑色;
2、根节点是黑色的;
3、每个叶节点(NIL)是黑色的;
4、如果一个结点是红色的,则它的两个子结点都是黑色的;
5、对每个结点,从该结点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点(此黑色结点的数目称为黑高)。
三、和平衡二叉树的区别
平衡二叉树是完全平衡的,而红黑树是局部平衡的,能确保没有一条路径会比其他路径长2倍,并且调整少,性能高,所以得到广泛应用,在STL里map和set都由红黑树实现。
四、节点定义
enum node_color{RED,BLACK}; typedef struct RBnode { int key;//数据信息 struct RBnode *left;//左孩子 struct RBnode *right;//右孩子 struct RBnode *p;//父节点 enum node_color color;//结点颜色 }
五、示例(图中所有空指针指向叶结点NIL)
六、旋转
目的:对红黑树进行插入和删除,可能会导致该树不在满足红黑树的性质,为了维护红黑树的性质,必须要改变树中某些结点的颜色以及指针结构。改变指针结构即通过旋转来完成,这是一种能保持二叉搜索树性质的搜索树局部操作。
1、左旋(LEFT_ROTATE)
图示:由三部完成该操作。
代码:
//将结点x左旋 RBnode *LEFT_ROTATE(RBnode *T, RBnode *x) { RBnode *y; y=x->right;//set y //step1:tunrn y's left subtree into x's right subtree x->right=y->left; if(y->left!=NIL) y->left->p=x; //step2:link x's parent to y y->p=x->p; if(x->p==NIL) T=y; else if(x==x->p->left) x->p->left=y; else x->p->right=y; //step3:put x on y's left y->left=x; x->p=y; return T; }
2、右旋(LEFT_ROTATE)
图示:由三部完成该操作。
代码:
//将结点x右旋 RBnode *RIGHT_ROTATE(RBnode *T, RBnode *x) { RBnode *y; y=x->p;//set y //step1:tunrn x's right subtree into y's left subtree y->left=x->right; if(x->right!=NIL) x->right->p=y; //step2:link y's parent to x x->p=y->p; if(y->p==NIL) T=x; else if(y==y->p->left) y->p->left=x; else y->p->right=x; //step3:put y on x's right x->right=y; y->p=x; return T; }
七、插入
插入操作与上一篇博文二叉排序树插入操作基本相同,除了细节之处稍有改变。
代码:
//在红黑树T上插入结点z RBnode *RB_INSERT(RBnode *T, RBnode *z) { RBnode *x; RBnode *y; y=NIL; x=T; while(x!=NIL) { y=x; if(z->key < x->key) x=x->left; else x=x->right; }
z.p=y; if(y==NIL) T=z; else if(z->key < y->key) y->left=z; else y->right=z;
z->left=NIL; z->right=NIL; z->color=RED; RB_INSERT_FIXUP(T,z); }
八、染色和调整
由于插入操作可能破坏红黑树性质,通过RB_INSERT_FIXUP(T,z)函数调整结点颜色和树的结构,使其保持红黑性质。——明晚继续完善
时间: 2024-10-04 06:03:16