红-黑树基本概念
红-黑树(Red-Black tree)是一种特殊的二叉查找树,因此具有二叉查找树的特征:任意一个节点所包含的关键字,大于左孩子的关键字,小于右孩子的关键字。树中每一个节点的颜色或者是黑色或者是红色,和AVL树一样具有平衡性。每一个空指针用一个外部结点来替代,红-黑树的性质可以描述为:
RB1:根节点和外部节点都是黑色。
RB2:在根至外部节点路径上,没有连续两个节点是红色。
RB3:在所有根至外部节点的路径上,黑色节点的数目都相同。
还有一种描述,其取决于父子指针的颜色,由父节点指向红色孩子的指针颜色为红,由父节点指向黑色儿子的指针颜色为黑。所以上述性质可以等价描述为:
RB1’:从内部节点指向外部节点的指针是黑色的。
RB2’:在跟至外部节点路径上,没有连续两个指针式红色的。
RB3’:在所有根至外部节点的路径上,黑色指针的数目都相同。
红-黑树示意图如下:
红-黑树的C++实现
对于节点颜色和指针颜色的性质描述,我们以下的讨论只针对节点颜色,相应的指针的颜色变化很容易推断出来。
1、红-黑树的节点
#pragma once
enum RBTreeColor{RED,BLACK};
template <typename T>
struct RBTreeNode
{
RBTreeColor color;
T key;
RBTreeNode<T>* leftChild;
RBTreeNode<T>* rightChild;
RBTreeNode<T>* parent;
RBTreeNode(T key, RBTreeColor c, RBTreeNode<T>* l,
RBTreeNode<T>* r, RBTreeNode<T>* p) :
key(value), color(c), leftChild(l), rightChild(r), parent(p) { }
RBTreeNode(T key, RBTreeColor c) : key(key), color(c),
leftChild(nullptr), rightChild(nullptr), parent(nullptr) { }
};
数据成员说明:
color:节点的颜色
key:关键字
leftChild:节点的左孩子
rightChild:节点的右孩子
parent:节点的父亲
使用enum定义了一个枚举类型对象,节点要么是黑色,要么是红色。
2、红-黑树类的接口
//***RBTree.h
#pragma once
#include<iostream>
#include"RBTreeNode.h"
using namespace std;
template <typename T>
class RBTree
{
public:
RBTree() : root(nullptr) { }
~RBTree() { destroy(root); }
// 前序、中序、后序遍历红-黑树
void preOrder() { preOrder(root); }
void inOrder() { inOrder(root); }
void postOrder() { postOrder(root); }
RBTreeNode<T>* find(const T& theKey) const;
// 查找最小和最大结点:返回结点的关键字指针。
T* minimum();
T* maximum();
// 将结点(theKey为节点关键字)插入到红黑树中
void insert(const T& theKey);
// 删除结点(theKey为节点关键字)
void erase(const T& theKey);
// 销毁红黑树
void destroy();
void output() { inOrder(root); cout << endl; }
private:
RBTreeNode<T>* root;
// 前序、中序、后序遍历红-黑树
void preOrder(RBTreeNode<T>* theRoot) const;
void inOrder(RBTreeNode<T>* theRoot) const;
void postOrder(RBTreeNode<T>* theRoot) const;
// 查找最小结点:返回以theRoot为根结点的红-黑树的最小结点
RBTreeNode<T>* minimum(RBTreeNode<T>* theRoot);
// 查找最大结点:返回以theRoot为根结点的红-黑树的最大结点
RBTreeNode<T>* maximum(RBTreeNode<T>* theRoot);
// 左旋
void rightRotate(RBTreeNode<T>* gu);
// 右旋
void leftRotate(RBTreeNode<T>* gu);
// 插入修正函数
void insertFixUp(RBTreeNode<T>* u);
// 删除修正函数
void eraseFixUp(RBTreeNode<T> *y, RBTreeNode<T> *py);
// 销毁红黑树
void destroy(RBTreeNode<T>* &theRoot);
};
对于插入和删除操作,首先和二叉查找树一样进行插入和删除操作,若造成红-黑树不平衡,再用insertFixUp()和eraseFixUp()进行修正。
3、旋转操作
当红-黑树失去平衡时,需要进行颜色变化和选择操作,类似于AVL的旋转,分为左旋和右旋两种:
leftRotate:
/*********************************
***leftRotate:
* gu pu
* / \ / \
* guL pu ----> gu puR
* / \ / \
* puL puR guL puL
**********************************/
template <typename T>
void RBTree<T>::leftRotate(RBTreeNode<T>* gu)
{
RBTreeNode<T>* pu = gu->rightChild;
gu->rightChild = pu->leftChild;
if (pu->leftChild != nullptr)
pu->leftChild->parent = gu;
pu->parent = gu->parent;
if (gu == root)
root = gu;
else
{
if (gu == gu->parent->leftChild)
gu->parent->leftChild = pu;
else
gu->parent->rightChild = pu;
}
pu->leftChild = gu;
gu->parent = pu;
}
rightRotate:
/*********************************
***rightRotate:
* gu pu
* / \ / \
* pu guR ----> puL gu
* / \ / \
* puL puR puR guR
**********************************/
template <typename T>
void RBTree<T>::rightRotate(RBTreeNode<T>* gu)
{
RBTreeNode<T>* pu = gu->leftChild;
gu->leftChild = pu->rightChild;
if (pu->rightChild != nullptr)
pu->rightChild->parent = gu;
pu->parent = gu->parent;
if (gu == root)
root = pu;
else
{
if (gu == gu->parent->leftChild)
gu->parent->leftChild = pu;
else
gu->parent->rightChild = pu;
}
pu->rightChild = gu;
gu->parent = pu;
}
4、插入
将一个节点插入到红-黑树中,和二叉查找树一样,但是因为节点是有颜色的,所以可能导致树失去平衡。如果插入的是“黑色”节点,将一定违反RB3(根到外部节点的黑色节点数目不等),而如果插入的是“红色”节点,有可能违反RB2(连续两个红色节点),也有可能不违反。所以,我们将新插入的节点染成“红色”,按照二叉查找树的方法插入到红-黑树中,若失去平衡,再进行修正。
插入:
template <typename T>
void RBTree<T>::insert(const T& theKey)
{
//创建新节点,并着色为“红色”
RBTreeNode<T>* newNode =
new RBTreeNode<T>(theKey, RED);
if (newNode == nullptr)
return;
RBTreeNode<T>* p = root,
*pp = nullptr;
while (p != nullptr)
{
pp = p;
if (theKey < p->key)
p = p->leftChild;
else if (theKey > p->key)
p = p->rightChild;
else
{
cerr << "不允许添加相同的节点!" << endl;
return;
}
}
newNode->parent = pp;
if (pp != nullptr)
{
if (theKey < pp->key)
pp->leftChild = newNode;
else
pp->rightChild = newNode;
}
else
root = newNode;
//修正添加newNode造成的红-黑树失去平衡
insertFixUp(newNode);
}
不平衡的类型可以通过检查新节点u、其父节点pu及其祖父节点gu来确定。RB2性质被破坏时,即连续两个红色节点:一个是u,另一个必定是它的父节点pu,因此pu存在。根据u的叔叔节点的颜色和父节点的位置,可以分为六种情况:
a、父节点是左孩子,叔叔节点是红色, 对应LLr或LRr,只需要进行颜色变化。将pu和guR变成“黑色”,gu变成“红色”。若gu的父节点存在且为“红色”,将转变成a、b、c、d、e或f情况,继续迭代。
代码:
if (guR && guR->color == RED)
{
pu->color = BLACK;
guR->color = BLACK;
gu->color = RED;
u = gu; //gu变成红色,可能gu的父节点也为红色,使得程序继续向上修正
continue;
}
b、父节点是左孩子,叔叔节点是黑色,u为右孩子,对应LRb情况。进行一次左旋操作既可转变成 c 情况。
代码:
if (u == pu->rightChild)
{
leftRotate(pu);
swap(pu, u); //为了接下来的右旋
}
c、父节点是左孩子,叔叔节点是黑色,u为左孩子,对应LLb情况。进行右旋操作,并将pu置为“黑色”,gu置为“红色”,即可恢复平衡。
代码:
gu->color = RED;
pu->color = BLACK;
rightRotate(gu);
d、父节点是右孩子,叔叔节点是“红色”,对应RRr或RLr,只需要进行颜色变化。将pu和guL变成“黑色”,gu变成“红色”。若gu的父节点存在且为“红色”,将转变成a、b、c、d、e或f情况,继续迭代。
代码:
if (guL && guL->color == RED)
{//RRr或RLr
pu->color = BLACK;
guL->color = BLACK;
gu->color = RED;
u = gu; //gu变成红色,可能gu的父节点也为红色,使得程序继续向上修正
continue;
}
e、父节点是右孩子,叔叔节点是黑色,u为左孩子,对应RLb情况。进行一次右旋操作既可转变成 f 情况。
代码:
if (u == pu->leftChild)
{
rightRotate(pu);
swap(pu, u); //为了接下来的左旋
}
f、父节点是右孩子,叔叔节点是黑色,u为右孩子,对应RRb情况。进行左旋操作,并将pu置为“黑色”,gu置为“红色”,即可恢复平衡。
代码:
gu->color = RED;
pu->color = BLACK;
leftRotate(gu);
插入之后的修正代码:
template <typename T>
void RBTree<T>::insertFixUp(RBTreeNode<T>* u)
{
RBTreeNode<T>* pu, *gu; //父节点,祖父节点
while ((pu = u->parent) && pu->color == RED)
{// 若“父节点存在,并且父节点的颜色是"红色"
gu = pu->parent;
//pu是gu的左孩子
if (pu == gu->leftChild)
{
RBTreeNode<T>* guR = gu->rightChild; //guR是u的叔叔节点,gu的右孩子
//Case1: 叔叔节点为红色; 对应LLr或LRr情况,只需要进行颜色变化
if (guR && guR->color == RED)
{
pu->color = BLACK;
guR->color = BLACK;
gu->color = RED;
u = gu; //gu变成红色,可能gu的父节点也为红色,使得程序继续向上修正
continue;
}
//叔叔为黑色,对应LLb和LRb情况
if (!guR || guR->color == BLACK)
{
//Case2: 叔叔为黑色,u是pu的右孩子
if (u == pu->rightChild)
{//左旋加右旋
leftRotate(pu);
swap(pu, u); //为了接下来的右旋
}
//Case3: 叔叔为黑色,u是pu的左孩子
gu->color = RED;
pu->color = BLACK;
rightRotate(gu);
}
}
//pu是gu的右孩子
else
{
RBTreeNode<T>* guL = gu->leftChild; //guL是u的叔叔节点,gu的左孩子
//Case1: 叔叔节点为红色; 对应RRr或RLr情况,只需要进行颜色变化
if (guL && guL->color == RED)
{//RRr或RLr
pu->color = BLACK;
guL->color = BLACK;
gu->color = RED;
u = gu; //gu变成红色,可能gu的父节点也为红色,使得程序继续向上修正
continue;
}
//叔叔为黑色,对应RRb和RLb情况
if (guL && guL->color == BLACK)
{
//Case2: 叔叔为黑色,u是pu的左孩子; RLb
if (u == pu->leftChild)
{//右旋加左旋
rightRotate(pu);
swap(pu, u); //为了接下来的左旋
}
//Case3: 叔叔为黑色,u是pu的右孩子; RRb
gu->color = RED;
pu->color = BLACK;
leftRotate(gu);
}
}
}
root->color = BLACK;
}
5、删除
首先找到要删除的节点,类似于对二叉查找树的删除操作,对红-黑树的节点进行删除,若删除的节点是“红色”,不会导致失去平衡,若删除的节点是“黑色”,则一定违反违反的是RB3(根到外部节点的数目减少)。
删除:
template <typename T>
void RBTree<T>::erase(const T& theKey)
{
RBTreeNode<T>* theNode = find(theKey);
if (theNode == nullptr)
return;
RBTreeColor color;
//当deleteNode有两个孩子
if (theNode->leftChild != nullptr &&
theNode->rightChild != nullptr)
{
//找到左子树最大节点替换待删除节点
RBTreeNode<T>* max = maximum(theNode->leftChild);
color = max->color;
theNode->key = max->key;
RBTreeNode<T>* max_child = max->leftChild; //只可能是有左孩子
if (max_child != nullptr)
max_child->parent = max->parent;
max->parent->leftChild = max_child;
if (color == BLACK)
eraseFixUp(theNode, theNode->parent);
delete max;
max == nullptr;
return;
}
//待删除节点最多只有一个孩子
RBTreeNode<T>* c; //c存下替换的节点
if (theNode->leftChild != nullptr)
c = theNode->leftChild;
else
c = theNode->rightChild;
color = theNode->color;
if (theNode != root)
{
if (theNode == theNode->parent->leftChild)
theNode->parent->leftChild = c;
else
theNode->parent->rightChild = c;
}
else
root = c;
if (c)
c->parent = theNode->parent;
if (color == BLACK)
eraseFixUp(c, theNode->parent);
delete theNode;
theNode = nullptr;
}
只有删除的节点为“黑色”时,才有可能造成不平衡。y是删除之后替代的节点,所以y为黑色,v是其兄弟节点,py是他们的父节点。y节点的阶(当前节点到一外部节点的路径上黑色节点的数目)比v节点的阶小1。根据v的颜色和v的孩子的颜色可以分为四种情况:
在进行删除时,主要有下面几种情形:
(1) y的兄弟为红色;
(2) y的兄弟节点w为黑色,且v节点的两个孩子都是黑色;
(3) y的兄弟节点w为黑色,且v的左孩子是红色,右孩子为黑色;
(4) y的兄弟节点w为黑色,且v的右孩子为黑色.
Case1:v是“红色”,必然py是黑色的,v的两个孩子是黑色的。将py置为“红色”,v置为“黑色”,对py进行左旋。更新v,将转变成2、3或4的情况。
代码:
if (v->color == RED)
{
py->color = RED;
v->color = BLACK;
leftRotate(py);
v = py->rightChild;
}
Case2:v是“黑色”,则py可能为黑也可能为红,v的左右孩子均为”黑色“。将v置为”红色“,即可使得y和v的阶相同,但是否恢复平衡取决于py和py的父节点的颜色,更新py为y,即可转变成1、2、3或4情况,继续迭代。
代码:
if ((!v->leftChild || v->leftChild->color == BLACK) &&
(!v->rightChild || v->rightChild->color == BLACK))
{
v->color = RED;
y = py;
py = py->parent;
}
Case3:v是“黑色”,则py可能为黑也可能为红,v的左孩子为”红色“,右孩子为”黑色“。将v置为”红色“,v的左孩子置为”黑色“,再对v进行右旋变化,更新v即可转变成4情况。
代码:
if (!y->rightChild || v->rightChild->color == BLACK)
{
v->color = RED;
if (v->leftChild)
v->leftChild->color = BLACK;
rightRotate(v);
y = py->rightChild;
}
Case4:v是”黑色“,则py可能为黑也可能为红,v的右孩子为”红色“,左孩子任意颜色。将v置为py的颜色,py置为”黑色“,再对py进行左旋变化,即可恢复平衡。
代码:
v->color = py->color;
if (v->rightChild)
v->rightChild->color = BLACK;
py->color = BLACK;
leftRotate(py);
y = root;
break;
删除之后的修正代码:
template <typename T>
void RBTree<T>::eraseFixUp(RBTreeNode<T>* y, RBTreeNode<T>* py)
{
RBTreeNode<T>* v; //y的兄弟节点
while ((!y || y->color == BLACK) && y != root)
{
//删除节点在父节点py的左子树
if (y == py->leftChild)
{
v = py->rightChild;
// Case 1: y的兄弟v是红色的
if (v->color == RED)
{
py->color = RED;
v->color = BLACK;
leftRotate(py);
v = py->rightChild;
}
// Case 2: y的兄弟v是黑色,且v的俩个孩子也都是黑色的
if ((!v->leftChild || v->leftChild->color == BLACK) &&
(!v->rightChild || v->rightChild->color == BLACK))
{
v->color = RED;
y = py;
py = py->parent;
}
else
{
// Case 3: y的兄弟v是黑色的,并且v的左孩子是红色,右孩子为黑色
if (!y->rightChild || v->rightChild->color == BLACK)
{
v->color = RED;
if (v->leftChild)
v->leftChild->color = BLACK;
rightRotate(v);
y = py->rightChild;
}
// Case 4: y的兄弟v是黑色的;并且v的右孩子是红色的,左孩子任意颜色
v->color = py->color;
if (v->rightChild)
v->rightChild->color = BLACK;
py->color = BLACK;
leftRotate(py);
y = root;
break;
}
}
//删除节点在父节点py的右子树
else
{
v = py->rightChild;
// Case 1: y的兄弟v是红色的
if (v->color == RED)
{
py->color = RED;
v->color = BLACK;
rightRotate(py);
v = py->leftChild;
}
// Case 2: y的兄弟v是黑色,且v的俩个孩子也都是黑色的
if ((!v->leftChild || v->leftChild->color == BLACK) &&
(!v->rightChild || v->rightChild->color == BLACK))
{
v->color = RED;
y = py;
py = py->parent;
}
else
{
// Case 3: y的兄弟v是黑色的,并且v的左孩子是红色,右孩子为黑色
if (!y->leftChild || v->leftChild->color == BLACK)
{
v->color = RED;
if (v->rightChild)
v->rightChild->color = BLACK;
leftRotate(v);
y = py->leftChild;
}
// Case 4: y的兄弟v是黑色的;并且v的右孩子是红色的,左孩子任意颜色
v->color = py->color;
if (v->leftChild)
v->leftChild->color = BLACK;
py->color = BLACK;
rightRotate(py);
y = root;
break;
}
}
}
if (y)
y->color = BLACK;
}
完整源码
#pragma once
#include<iostream>
#include"RBTreeNode.h"
using namespace std;
template <typename T>
class RBTree
{
public:
RBTree() : root(nullptr) { }
~RBTree() { destroy(root); }
// 前序、中序、后序遍历红-黑树
void preOrder() { preOrder(root); }
void inOrder() { inOrder(root); }
void postOrder() { postOrder(root); }
RBTreeNode<T>* find(const T& theKey) const;
// 查找最小和最大结点:返回结点的关键字指针。
T* minimum();
T* maximum();
// 将结点(theKey为节点关键字)插入到红黑树中
void insert(const T& theKey);
// 删除结点(theKey为节点关键字)
void erase(const T& theKey);
// 销毁红黑树
void destroy();
void output() { inOrder(root); cout << endl; }
private:
RBTreeNode<T>* root;
// 前序、中序、后序遍历红-黑树
void preOrder(RBTreeNode<T>* theRoot) const;
void inOrder(RBTreeNode<T>* theRoot) const;
void postOrder(RBTreeNode<T>* theRoot) const;
// 查找最小结点:返回以theRoot为根结点的红-黑树的最小结点
RBTreeNode<T>* minimum(RBTreeNode<T>* theRoot);
// 查找最大结点:返回以theRoot为根结点的红-黑树的最大结点
RBTreeNode<T>* maximum(RBTreeNode<T>* theRoot);
// 左旋
void rightRotate(RBTreeNode<T>* gu);
// 右旋
void leftRotate(RBTreeNode<T>* gu);
// 插入修正函数
void insertFixUp(RBTreeNode<T>* u);
// 删除修正函数
void eraseFixUp(RBTreeNode<T> *y, RBTreeNode<T> *py);
// 销毁红黑树
void destroy(RBTreeNode<T>* &theRoot);
};
template <typename T>
void RBTree<T>::preOrder(RBTreeNode<T>* theRoot) const
{
if (theRoot != nullptr)
{
cout << theRoot->key << " ";
preOrder(theRoot->leftChild);
preOrder(theRoot->rightChild);
}
}
template <typename T>
void RBTree<T>::inOrder(RBTreeNode<T>* theRoot) const
{
if (theRoot != nullptr)
{
inOrder(theRoot->leftChild);
cout << theRoot->key << " ";
inOrder(theRoot->rightChild);
}
}
template <typename T>
void RBTree<T>::postOrder(RBTreeNode<T>* theRoot) const
{
if (theRoot != nullptr)
{
postOrder(theRoot->leftChild);
postOrder(theRoot->rightChild);
cout << theRoot->key << " ";
}
}
template <typename T>
RBTreeNode<T>* RBTree<T>::find(const T& theKey) const
{
RBTreeNode<T>* p = root;
while (p != nullptr)
{
if (theKey < p->key)
p = p->leftChild;
else if (theKey > p->key)
p = p->rightChild;
else
return p;
}
return nullptr;
}
template <typename T>
T* RBTree<T>::minimum()
{
RBTreeNode<T>* min = minimum(root);
if (min != nullptr)
return &min->key;
return nullptr;
}
template <typename T>
RBTreeNode<T>* RBTree<T>::minimum(RBTreeNode<T>* theRoot)
{
RBTreeNode<T>* p = theRoot,
*pp = nullptr;
while (p != nullptr)
{
pp = p;
p = p->leftChild;
}
return pp;
}
template <typename T>
T* RBTree<T>::maximum()
{
RBTreeNode<T>* max = maximum(root);
if (max != nullptr)
return &max->key;
return nullptr;
}
template <typename T>
RBTreeNode<T>* RBTree<T>::maximum(RBTreeNode<T>* theRoot)
{
RBTreeNode<T>* p = theRoot,
*pp = nullptr;
while (p != nullptr)
{
pp = p;
p = p->rightChild;
}
return pp;
}
/*********************************
***rightRotate:
* gu pu
* / \ / \
* pu guR ----> puL gu
* / \ / \
* puL puR puR guR
**********************************/
template <typename T>
void RBTree<T>::rightRotate(RBTreeNode<T>* gu)
{
RBTreeNode<T>* pu = gu->leftChild;
gu->leftChild = pu->rightChild;
if (pu->rightChild != nullptr)
pu->rightChild->parent = gu;
pu->parent = gu->parent;
if (gu == root)
root = pu;
else
{
if (gu == gu->parent->leftChild)
gu->parent->leftChild = pu;
else
gu->parent->rightChild = pu;
}
pu->rightChild = gu;
gu->parent = pu;
}
/*********************************
***leftRotate:
* gu pu
* / \ / \
* guL pu ----> gu puR
* / \ / \
* puL puR guL puL
**********************************/
template <typename T>
void RBTree<T>::leftRotate(RBTreeNode<T>* gu)
{
RBTreeNode<T>* pu = gu->rightChild;
gu->rightChild = pu->leftChild;
if (pu->leftChild != nullptr)
pu->leftChild->parent = gu;
pu->parent = gu->parent;
if (gu == root)
root = gu;
else
{
if (gu == gu->parent->leftChild)
gu->parent->leftChild = pu;
else
gu->parent->rightChild = pu;
}
pu->leftChild = gu;
gu->parent = pu;
}
template <typename T>
void RBTree<T>::insert(const T& theKey)
{
//创建新节点,并着色为“红色”
RBTreeNode<T>* newNode =
new RBTreeNode<T>(theKey, RED);
if (newNode == nullptr)
return;
RBTreeNode<T>* p = root,
*pp = nullptr;
while (p != nullptr)
{
pp = p;
if (theKey < p->key)
p = p->leftChild;
else if (theKey > p->key)
p = p->rightChild;
else
{
cerr << "不允许添加相同的节点!" << endl;
return;
}
}
newNode->parent = pp;
if (pp != nullptr)
{
if (theKey < pp->key)
pp->leftChild = newNode;
else
pp->rightChild = newNode;
}
else
root = newNode;
//修正添加newNode造成的红-黑树失去平衡
insertFixUp(newNode);
}
template <typename T>
void RBTree<T>::insertFixUp(RBTreeNode<T>* u)
{
RBTreeNode<T>* pu, *gu; //父节点,祖父节点
while ((pu = u->parent) && pu->color == RED)
{// 若“父节点存在,并且父节点的颜色是"红色"
gu = pu->parent;
//pu是gu的左孩子
if (pu == gu->leftChild)
{
RBTreeNode<T>* guR = gu->rightChild; //guR是u的叔叔节点,gu的右孩子
//Case1: 叔叔节点为红色; 对应LLr或LRr情况,只需要进行颜色变化
if (guR && guR->color == RED)
{
pu->color = BLACK;
guR->color = BLACK;
gu->color = RED;
u = gu; //gu变成红色,可能gu的父节点也为红色,使得程序继续向上修正
continue;
}
//叔叔为黑色,对应LLb和LRb情况
if (!guR || guR->color == BLACK)
{
//Case2: 叔叔为黑色,u是pu的右孩子
if (u == pu->rightChild)
{//左旋加右旋
leftRotate(pu);
swap(pu, u); //为了接下来的右旋
}
//Case3: 叔叔为黑色,u是pu的左孩子
gu->color = RED;
pu->color = BLACK;
rightRotate(gu);
}
}
//pu是gu的右孩子
else
{
RBTreeNode<T>* guL = gu->leftChild; //guL是u的叔叔节点,gu的左孩子
//Case1: 叔叔节点为红色; 对应RRr或RLr情况,只需要进行颜色变化
if (guL && guL->color == RED)
{//RRr或RLr
pu->color = BLACK;
guL->color = BLACK;
gu->color = RED;
u = gu; //gu变成红色,可能gu的父节点也为红色,使得程序继续向上修正
continue;
}
//叔叔为黑色,对应RRb和RLb情况
if (guL && guL->color == BLACK)
{
//Case2: 叔叔为黑色,u是pu的左孩子; RLb
if (u == pu->leftChild)
{//右旋加左旋
rightRotate(pu);
swap(pu, u); //为了接下来的左旋
}
//Case3: 叔叔为黑色,u是pu的右孩子; RRb
gu->color = RED;
pu->color = BLACK;
leftRotate(gu);
}
}
}
root->color = BLACK;
}
template <typename T>
void RBTree<T>::erase(const T& theKey)
{
RBTreeNode<T>* theNode = find(theKey);
if (theNode == nullptr)
return;
RBTreeColor color;
//当deleteNode有两个孩子
if (theNode->leftChild != nullptr &&
theNode->rightChild != nullptr)
{
//找到左子树最大节点替换待删除节点
RBTreeNode<T>* max = maximum(theNode->leftChild);
color = max->color;
theNode->key = max->key;
RBTreeNode<T>* max_child = max->leftChild; //只可能是有左孩子
if (max_child != nullptr)
max_child->parent = max->parent;
max->parent->leftChild = max_child;
if (color == BLACK)
eraseFixUp(theNode, theNode->parent);
delete max;
max == nullptr;
return;
}
//待删除节点最多只有一个孩子
RBTreeNode<T>* c; //c存下替换的节点
if (theNode->leftChild != nullptr)
c = theNode->leftChild;
else
c = theNode->rightChild;
color = theNode->color;
if (theNode != root)
{
if (theNode == theNode->parent->leftChild)
theNode->parent->leftChild = c;
else
theNode->parent->rightChild = c;
}
else
root = c;
if (c)
c->parent = theNode->parent;
if (color == BLACK)
eraseFixUp(c, theNode->parent);
delete theNode;
theNode = nullptr;
}
template <typename T>
void RBTree<T>::eraseFixUp(RBTreeNode<T>* y, RBTreeNode<T>* py)
{
RBTreeNode<T>* v; //y的兄弟节点
while ((!y || y->color == BLACK) && y != root)
{
//删除节点在父节点py的左子树
if (y == py->leftChild)
{
v = py->rightChild;
// Case 1: y的兄弟v是红色的
if (v->color == RED)
{
py->color = RED;
v->color = BLACK;
leftRotate(py);
v = py->rightChild;
}
// Case 2: y的兄弟v是黑色,且v的俩个孩子也都是黑色的
if ((!v->leftChild || v->leftChild->color == BLACK) &&
(!v->rightChild || v->rightChild->color == BLACK))
{
v->color = RED;
y = py;
py = py->parent;
}
else
{
// Case 3: y的兄弟v是黑色的,并且v的左孩子是红色,右孩子为黑色
if (!y->rightChild || v->rightChild->color == BLACK)
{
v->color = RED;
if (v->leftChild)
v->leftChild->color = BLACK;
rightRotate(v);
y = py->rightChild;
}
// Case 4: y的兄弟v是黑色的;并且v的右孩子是红色的,左孩子任意颜色
v->color = py->color;
if (v->rightChild)
v->rightChild->color = BLACK;
py->color = BLACK;
leftRotate(py);
y = root;
break;
}
}
//删除节点在父节点py的右子树
else
{
v = py->rightChild;
// Case 1: y的兄弟v是红色的
if (v->color == RED)
{
py->color = RED;
v->color = BLACK;
rightRotate(py);
v = py->leftChild;
}
// Case 2: y的兄弟v是黑色,且v的俩个孩子也都是黑色的
if ((!v->leftChild || v->leftChild->color == BLACK) &&
(!v->rightChild || v->rightChild->color == BLACK))
{
v->color = RED;
y = py;
py = py->parent;
}
else
{
// Case 3: y的兄弟v是黑色的,并且v的左孩子是红色,右孩子为黑色
if (!y->leftChild || v->leftChild->color == BLACK)
{
v->color = RED;
if (v->rightChild)
v->rightChild->color = BLACK;
leftRotate(v);
y = py->leftChild;
}
// Case 4: y的兄弟v是黑色的;并且v的右孩子是红色的,左孩子任意颜色
v->color = py->color;
if (v->leftChild)
v->leftChild->color = BLACK;
py->color = BLACK;
rightRotate(py);
y = root;
break;
}
}
}
if (y)
y->color = BLACK;
}
template <typename T>
void RBTree<T>::destroy()
{
destroy(root);
}
template <typename T>
void RBTree<T>::destroy(RBTreeNode<T>* &theRoot)
{
if (theRoot == nullptr)
return;
destroy(theRoot->leftChild);
destroy(theRoot->rightChild);
delete theRoot;
theRoot = nullptr;
}
本文介绍了红-黑树的基本概念,包括其性质和颜色规则,并详细阐述了红-黑树的C++实现,包括节点定义、插入和删除操作。插入时,通过分析节点颜色和位置,对六种不平衡情况进行处理。删除操作则根据删除节点的颜色和兄弟节点的情况,调整颜色和旋转以恢复平衡。文章最后给出了完整的C++源码。
707

被折叠的 条评论
为什么被折叠?



