本文分为3部分,第一部分实现一棵红黑树的左旋/右旋/插入和删除。
第二部分将第一部分中的红黑树扩展成一棵区间树。
第三部分是对区间树(插入/删除/搜索)的测试。
part 1 红黑树的插入删除操作
part 2 区间树重叠区间查找
part 1 红黑树的插入删除操作
1.红黑树特性
-
满足二叉查找树特征:对于任意结点x,x.key>=x.left.key, x.key<=x.rightkey
-
根节点是黑色
-
NIL结点为黑色
-
若一个结点为红,则它的子结点为黑
-
任意结点x的所有子孙路径,黑结点数目相同
2.红黑树基本定义
#define RED 0 #define BLACK 1 typedef int Type; typedef struct{ unsigned char color; Type key; struct RBNode *left; struct RBNode *right; struct RBNode *parent; }RBNode,*RBTree; typedef struct { RBNode *node; }RBRoot;
3.对结点x左旋leftRotate
算法步骤:
(1)找到x的孩子: y=x->right
(2)y的孩子过继: x->right=y->left;
if(y->left!=NULL) y->left->parent=x;
(3)y的新父子关系: y->parent=x->parent;
x->parent->child=y;
【注意:若x.parent=NULL,则x为根,故此时将y设置为根】
(4)x和y的父子关系:y->left=x; x->parent=y;
void leftRotate(RBRoot *root, RBNode *x)
{
RBNode *y=x->right;
x->right=y->left;
if(y->left!=NULL)
y->left->parent=x;
y->parent=x->parent;
if(x->parent==NULL) root=y;
else if(x->parent->left==x) x->parent->left=y;
else x->parent->right=y;
x->parent=y;
y->left=x;
}
3.对结点y右旋rightRotate
【将左旋中,x<->y,left<->right,即可】
void rightRotate(RBRoot *root, RBNode *y)
{
RBNode *x=y->left;
y->left=x->right;
if(x->right!=NULL)
x->right->parent=y;
x->parent=y->parent;
if(y->parent==NULL) root=x;
else if(y->parent->right==y) y->parent->right=x;
else y->parent->left=x;
y->parent=x;
x->right=y;
}
4.插入操作insert
&&insertFixUp
(1)将z结点按BST树规则插入红黑树中,z是叶子结点(insert)
(2)将z涂红
(3)调整使其满足红黑树的性质(insertFixUp)
//插入算法insert
void insert(RBRoot *root,RBNode *node)
{
RBNode *y=NULL;
RBNode *x=root->node;
while(x!=NULL)
{
y = x;
if (node->key < x->key) x = x->left;
else x = x->right;
}
node->parent=y;
if(y!=NULL)
if(node->key<y->key) y->left=node;
else y->right=node;
else root->node=node;
node->color=RED;
insertFixUp(root,node);
}
调整算法insertFixUp步骤:
(1)判断是否需要调整:若z为根,将其涂黑,结束;
若z不为根,且p[z]为黑,无需调整,结束;
若z不为根,且p[z]为红,则需调整
【此时隐含条件:p[z]不为根,p[p[z]]存在且为黑】。
(2)调整方法:
【case1~3 p[z]为左孩子】
case 1: z的叔叔为RED;
step1:z的爸爸和叔叔变黑,z的祖父变红;
step2:z上溯到祖父处,z=p[p[z]]
step3:继续循环,最多上溯到根。若上溯到根,此时将根涂黑,终止
case 2: z的叔叔为BLACK且z为右孩子;
step1:z=p[z]
step2:左旋z,等价变换为case 3
case 3: z的叔叔为BLACK且z为左孩子;
step1:z的爸爸变黑,祖父变红
step2:右旋z的祖父
step3:调整终止
【case4~6 p[z]为右孩子】
case 4: z的叔叔为RED;
step1:z的爸爸和叔叔变黑,z的祖父变红;
step2:z上溯到祖父处,z=p[p[z]]
step3:继续循环,最多上溯到根。若上溯到根,此时将根涂黑,终止
case 5: z的叔叔为BLACK且z为左孩子;
step1:z=p[z]
step2:右旋z,等价变换为case 6
case 6: z的叔叔为BLACK且z为右孩子;
step1:z的爸爸变黑,祖父变红
step2:左旋z的祖父
step3:调整终止
//调整算法insertFixUp
void insertFixUp(RBRoot *root,RBNode *node)
{
RBNode *parent,*gparent;
//父结点存在且为红色
while((parent=node->parent)&&(node->parent->color==RED)){
gparent=parent->parent;
//case1~3 p[z]为左孩子
if(parent==gparent->left){
//case1:z的叔叔为RED
if(gparent->right->color ==RED){
parent->color=BLACK;
gparent->right->color=BLACK;
gparent->color=RED;
node=gparent;
continue;
}
//case2:z的叔叔为BLACK,且z为右孩子
if((gparent->right->color==BLACK)&&(node==node->parent->right)){
node=node->parent;
leftRotate(root,node);
}
//case 3:z的叔叔y是黑色,且z为左孩子
if((gparent->right->color==BLACK)&&(node==node->parent->left)){
node->parent->color=BLACK;
node->parent->parent->color=RED;
rightRotate(root,node->parent->parent);
break;
}
}
//case4~6:p[z]为右孩子
else{
//case 4:z的叔叔为RED
if(gparent->left->color==RED){
parent->