RBTRee 插入节点:
- 首先用BSTree的方法构造节点,然后创建一个真实的空节点,让所有没有真是子节点的节点都指向这个真实的空节点,而不是nullptr。插入之后的调平颜色和高度是问题的关键。
- 以左子树为例,右子树为镜像操作。
- 先找到叔伯节点,若叔伯节点不为空且颜色为红色,则父节点颜色改为黑色,叔伯节点变为黑色,爷爷节点变为红色,然后插入节点由原来的位置变成爷爷节点,然后向上回溯。这是一种情况。
- 左边的直线插入 ‘ / ’ ,将父节点的颜色变为黑色,爷爷节点的颜色变成红色,然后进行一个右单旋转。如果是 ‘ < ’ 这种情况的内侧插入,先进行一个左单旋转,将其转化成 ‘ / ’ 这个情况,再进行一个右单旋转。
- 调节到最后,将根节点变成黑色,即可。
bool RBTree<Type>::Insert(RBNode<Type>*& t, const Type& x)
{
//按bst的规则插入节点
RBNode<Type>* s = t;
RBNode<Type>* pr = Nil;
while (s != Nil)
{
if (s->data == x)
return false;
pr = s;
if (s->data > x)
s = s->leftChild;
else
s = s->rightChild;
}
//创建x值节点
s = _Buynode(x);
//插入节点
if (pr == Nil)
t = s;
else if (x < pr->data)
pr->leftChild = s;
else
pr->rightChild = s;
s->parent = pr;
Insert_Fixup(t, s);
return true;
}
void RBTree<Type>::Insert_Fixup(RBNode<Type>*& t, RBNode<Type>* x)
{
while (x->parent->color == RED)
{
RBNode<Type>*s = Nil;
if (x->parent == x->parent->parent->leftChild)//左分支
{
s = x->parent->parent->rightChild;//找到叔伯节点
//3.
if (s != Nil && s->color == RED)
{
x->parent->color = BLACK;
s->color = BLACK;
x->parent->parent->color = RED;
x = x->parent->parent;
}
//2.内侧插入 拐弯插入 ‘<’
else
{
if (x == x->parent->rightChild) //先变成 ‘/’
{
//x->parent->parent->color = RED;
//x->color = BLACK;
x = x->parent;
RotateL(t, x);
}
//1.直线插入 更改 PG的颜色
x->parent->color = BLACK;
x->parent->parent->color = RED;
RotateR(t, x->parent->parent);
}
}
else//右分支
{
s = x->parent->parent->leftChild;//找到书博节点
//3.
if (s != Nil&&s->color == RED)
{
x->parent->color = BLACK;
s->color = BLACK;
x->parent->parent->color = RED;
x = x->parent->parent;
}
else
{
//2.
if (x == x->parent->leftChild)
{
x = x->parent;
RotateR(t, x);
}
//1.
x->parent->color = BLACK;
x->parent->parent->color = RED;
RotateL(t, x->parent->parent);
}
}
}
t->color = BLACK;
}
RBTree 删除节点的情况一共有六种:
1.被删除节点无子节点,且被删除节点为红色,则直接删除。
2.被删除节点无子节点,且被删除节点为黑色。
-
*a1.如果它的兄弟节点为黑色,且兄弟节点存在和自己相同方向的子节点是红色(如果有子节点必然是红色),则进行左单旋转。
a2.方向不同的红色子节点,双旋转。
如果兄弟节点无子节点* -
*b1.兄弟节点没有子节点,父节点为红色,兄弟为黑色,将兄弟换成红色,父换成黑色
b2.兄弟节点为红色,则父节点肯定为黑色,继续向上追溯,遇到别的情况直接进行调整*。
3.被删除节点有一个子节点,且被删除节点为红色。这个是不存在的,因为这样子不满足黑色分支都一样多。
4.被删除节点有一个子节点,且被删除为黑色,
5&6.被删除节点有两个子节点,且被删除节点为黑色或者红色,这种情况被转化成前面的1,2,4这三种之一。
所以删除只有三种大情况。
bool RBTree<Type>::Remove(RBNode<Type>*& t, const Type& key)
{
RBNode<Type>*p = t, *c; // c-----Child
while (p != Nil)
{
if (p->data == key)
break;
if (key < p->data)
p = p->leftChild;
else
p = p->rightChild;
}
if (p == Nil)
return false;
if (p->leftChild != Nil&&p->rightChild != Nil)
{
//找到要替换的值的节点位置
RBNode<Type>*q;
q = p->rightChild;
while (q->leftChild != Nil)
q = q->leftChild;
p->data = q->data;
p = q;
}
if (p->leftChild != Nil)
c = p->leftChild;
else
c = p->rightChild;
c->parent = p->parent;
if (p->parent == Nil)//只有根节点的父不为空
t = c;
else if (p == p->parent->leftChild)
p->parent->leftChild = c;
else
p->parent->rightChild = c;
//调整平衡
if (p->color == BLACK)
Remove_fixup(t, c);
delete p;
return true;
}
/
template<class Type>
void RBTree<Type>::Remove_fixup(RBNode<Type>*& t, RBNode<Type>* x)
{
RBNode<Type>* w;
while (x != t && x->color == BLACK)
{
w = x->parent->rightChild; //w是删除的节点的兄弟节点
//第二大类的1 2 3
if (x == x->parent->leftChild)//左边
{
//4.
if (w->color == RED)
{
w->color = BLACK;
x->parent->color = RED;
w = w->leftChild;
RotateL(t, x->parent);
}
//3.
if (w->leftChild->color != RED&&w->rightChild->color != RED)
{
w->color = RED;
x = x->parent;
}
else
{
//2.
if (w->leftChild != Nil)//先将'>'变成 '\'
{
w->leftChild->color = BLACK;
w->color = RED;
w = w->leftChild;
RotateR(t, w->parent);
}
//1.
w->color = x->parent->color;
x->parent->color = BLACK;
w->rightChild->color = BLACK;
RotateL(t, x->parent);
x = t;
}
}
else
{
//4.
if (w->color == RED)
{
w->color = BLACK;
x->parent->color = RED;
w = w->rightChild;
RotateR(t, x->parent);
}
//3.
if (w->leftChild->color != RED&&w->rightChild->color != RED)
{
w->color = RED;
x = x->parent;
}
else
{
//2.
if (w->rightChild != Nil)//先将'>'变成 '\'
{
w->rightChild->color = BLACK;
w->color = RED;
w = w->rightChild;
RotateL(t, w->parent);
}
//1.
w->color = x->parent->color;
x->parent->color = BLACK;
w->leftChild->color = BLACK;
RotateR(t, x->parent);
x = t;
}
}
}
x->color = BLACK;
}
代码如上。