紅-黑樹——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;
}
發佈了30 篇原創文章 · 獲贊 22 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章