红-黑树——C++实现

本文介绍了红-黑树的基本概念,包括其性质和颜色规则,并详细阐述了红-黑树的C++实现,包括节点定义、插入和删除操作。插入时,通过分析节点颜色和位置,对六种不平衡情况进行处理。删除操作则根据删除节点的颜色和兄弟节点的情况,调整颜色和旋转以恢复平衡。文章最后给出了完整的C++源码。

红-黑树基本概念



红-黑树(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情况,继续迭代。
LLr或LRr
代码:

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);

LLb和LRb
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;
}

RRr或RLr
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);

RRb和RLb

插入之后的修正代码:

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;
}

Case1

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;
}

Case2

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;
}

Case3

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;

Case4

删除之后的修正代码:

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值