上一章讲述了红黑树得相关性质,我们了解到红黑树确实是平衡二叉树,在时间复杂度为O(lg(n)),比二叉搜索树性能更好,性能变好的前提是算法更加复杂了,下面讲述红黑树的插入和删除操作,希望对大家有所帮助。
红黑树的插入
红黑树的插入操作和二叉搜索树大致相同,不同点是在将节点x插入红黑树后,此时的红黑树可能会违反红黑树的相关性质,我们需要对其进行调整,调整的方法有两种:变色和旋转。下面着重讲述一下旋转操作。
旋转
旋转分为左旋和右旋,具体示意图如下:
旋转变换不会改变红黑树的中序遍历。
由上图中旋转变换的原理,可以写出旋转变换的伪代码:
LEFT-ROTATE(T,x)
y=x.right
x.right=y.left
if y.left !=T.nil
y.left.p=x
y.p=x.p
if(x.p==T.nil)
T.root=y
elseif x==x.p.left
x.p.left=y
else
x.p.right=y
y.left=x;
x.p=y
旋转变换c代码:
void left_rotate(tree_node *x) //红黑树的左旋转
{
tree_node *y;
y=x->right;
x->right=y->left;
if(y->left!=NULL)
{
y->left->parent=x;
}
if(x->parent->left==x)
{
x->parent->left=y;
}
else
{
x->parent->right=y;
}
y->parent=x->parent;
y->left=x;
x->parent=y;
}
这里我们需要注意一点:当红色节点为单支节点时,该红色节点一定为为叶子节点。
在进行插入操作时,我们需要将插入节点的颜色赋成红色,因为红色节点插入后不会破坏红黑树性质5,但是仍然会破坏性质2或者性质4,但是仅仅出现一条性质的破坏。如果插入黑色节点,则破坏的性质位置
如下三种情况是不可能出现的:
由红黑树的第五条性质可以知道,任意节点x的子分支结构都具有相同的黑高,如果是上述三种情况,不可能满足该性质。
综上所述,插入操作可以分为如下三种情况:
情况1:如果插入节点的父节点为黑色,则直接插入即可,不会影响红黑树的性质。
情况2:如果插入节点的父节点为红色,叔节点为红色时
情况3:如果插入节点的父节点为红色,叔节点为黑色,且待删除节点为父节点的有孩子
这一步是为了将情况3变成情况4,再利用情况4的解决方法解决该问题
由此红黑树插入操作就结束了。
c代码如下:
void RB_insert(tree_node *x,tree_node *z) //插入红黑树的一个节点
{
tree_node *y,*y1;
z->color=1; //将插入节点设为红色
y1=x; //保留当前x的指针位置
while(x!=NULL)
{
y=x;
if(x->data>z->data)
{
x=x->left;
}
else
{
x=x->right;
}
}
if(y->data>z->data) //判断z为左节点还是右节点
{
y->left=z;
}
else
{
y->right=z;
}
z->parent=y;
z->left=NULL;
z->right=NULL;
RB_fix(z);
}
void RB_fix(tree_node *z) //重新着色
{
while(z->parent->color!=0) //当红黑树性质恢复时,z节点一定为红色,则其父节点一定为黑色,作为循环结束标志
{
if(z->parent->parent->left==z->parent) //判断父节点是否是祖父节点的左孩子
{
if(z->parent->parent->right->color==1) //情况1,叔节点为红色
{
z->parent->color=0;
z->parent->parent->color=1;
z->parent->parent->left->color=0;
z=z->parent->parent;
}
else if(z->parent->right==z) //情况2,叔节点为黑色,且插入节点为父节点的右孩子
{
left_rotate(z);
}
else //情况3,叔节点为黑色,且插入节点为父节点的左孩子
{
right_rotate(z);
z->parent->color=0;
z->parent->right->color=1;
}
}
else //判断父节点是否是祖父节点的左孩子
{
if(z->parent->parent->left->color==1)
{
z->parent->color=0;
z->parent->parent->color=1;
z->parent->parent->left->color=0;
z=z->parent->parent;
}
else if(z->parent->left==z)
{
right_rotate(z);
}
else
{
left_rotate(z);
z->parent->color=0;
z->parent->left->color=1;
}
}
}
}