红黑树是一种二叉查找树,但在每个结点上增加一个存储位表示结点的颜色,可以是RED或者BLACK。通常对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出两倍,因而是平衡的。
树中的每个结点包含五个域:color、key、left、right、p。如果某结点没有一个子结点或父结点,则该结点相应得指针(p)域包含值NIL。我们将把这些 NIL 视为指向二叉查找树的外结点(叶子)的指针,而把带关键字的结点视为树的内结点。
一棵二叉查找树如果满足下面的红黑性质,则为一颗红黑树:
- 每个结点或是红的,或是黑的
- 根结点是黑的
- 每个叶结点(NIL)是黑的
- 如果一个结点是红的,则它的两个子结点都是黑的
- 对每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点
1. 旋转
当在含 n 个关键字的红黑树上运行时,查找树操作 TREE-INSERT(插入)和 TREE-DELETE(删除)的时间为O(lgn)。由于这两个操作对树作了修改,结果可能违反红黑树的性质。为保持这些性质,就要改变树中某些结点的颜色以及指针结构。
指针结构的修改是通过旋转来完成的,这是一种能保持二叉查找树性质的查找树局部操作。下面给出了两种旋转:左旋和右旋。当在某个结点 x 上做左旋时,我们假设它的右孩子 y 不是 nil[T];x 可以为树内任意右孩子不是 nil[T] 的结点。左旋以 x 到y 之间的链为“支轴”进行。它使 y 成为该子树新的根,x 成为 y 的左孩子,而 y 的左孩子则成为 x 的右孩子,如下图所示。
旋转过程代码:
//左旋
void RotateLeft(rb_node *head,rb_node *ptr)
{
rb_node *newroot = ptr->rightchild;//#
newroot->parent = ptr->parent; // 1
ptr->rightchild = newroot->leftchild; // #
if(newroot->leftchild != NULL)
{
newroot->leftchild->parent = ptr; //2
}
newroot->leftchild = ptr; // #
if(ptr == head->parent) // ptr => root;
{
head->parent = newroot;
}
else
{
if(ptr->parent->leftchild == ptr)
{
ptr->parent->leftchild = newroot;
}
else
{
ptr->parent->rightchild = newroot;
}
}
ptr->parent = newroot; // 3
}
//右旋
void RotateRight(rb_node *head, rb_node *ptr)
{
rb_node *newroot = ptr->leftchild;
newroot->parent = ptr->parent; // 1
ptr->leftchild = newroot->rightchild;
if(newroot->rightchild != NULL)
{
newroot->rightchild->parent = ptr; //2
}
newroot->rightchild = ptr;
if(ptr == head->parent)
{
head->parent = newroot;
}
else
{
if(ptr->parent->leftchild == ptr)
{
ptr->parent->leftchild = newroot;
}
else
{
ptr->parent->rightchild = newroot;
}
}
ptr->parent = newroot; // 3
}
2. 插入
在红黑树中插入一个新的结点,为保证红黑树的性质,将新插入的结点着为红色。
回溯:如果在左边插入,找双亲的双亲的右结点;如果在右边插入,找双亲的双亲的左结点。
双亲:1)红色 --> 找双亲的双亲的左结点 --> :a.红色 --> 将双亲还有双亲的双亲的左结点变红,双亲的双亲变黑
b.黑色 --> 旋转
2)黑色 --> 结束
调整结点颜色代码:
void Adjust_RBTree(RBTree &myt,rb_node *ptr)
{
rb_node *_X,*_Y;
for(_X = ptr; _X->parent != myt.head && _X->parent->color == RED;)
{
if(_X->parent->parent->rightchild == _X->parent) //_X的爷爷结点的右节点是否为_X的父亲节点
{
_Y = _X->parent->parent->leftchild;
if(_Y->color == RED)
{
_Y->color = BLACK;
_X->parent->color = BLACK;
_X->parent->parent->color = RED;
_X = _X->parent->parent;
}
else
{
if(_X->parent->leftchild == _X)
{
_X = _X->parent;
RotateRight(myt.head,_X);
}
_X->parent->color = BLACK;
_X->parent->parent->color = RED;
RotateLeft(myt.head,_X->parent->parent);
}
}
else // left; _X的爷爷结点的左节点是否为_X的父亲节点
{
_Y = _X->parent->parent->rightchild;
if(_Y->color == RED)
{
_Y->color = BLACK;
_X->parent->color = BLACK;
_X->parent->parent->color = RED;
_X = _X->parent->parent;
}
else //_Y->color == BLACK
{
if(_X->parent->rightchild == _X)
{
_X = _X->parent;
RotateLeft(myt.head,_X);
}
_X->parent->color = BLACK;
_X->parent->parent->color = RED;
RotateRight(myt.head,_X->parent->parent);
}
}
}
myt.head->parent->color = BLACK;
}
3. 删除
(未完待续)