再论红黑树

红黑树真TM是一个非常难的数据结构,至少对我这种非计算机专业的业余爱好者来说是非常难的,正好这段时间想学学这个,虽然中间断断续续的学了一点点,但是都没有彻底的去熟悉甚至去实现这样一棵红黑树,直到今天,才真正的实现了一棵红黑树。为了使自己所学的东西更加的巩固,于是决定不自量力,写篇博客,若有错漏,请指出,勿喷,毕竟本人只是一个非专业型娱乐辣鸡选手。

什么是红黑树

红黑树是什么?之前我曾经写过一篇关于二叉搜索树的博客,红黑树其实就是一棵非严格平衡的二叉搜索树,它有以下五点性质:

  1. 它所有结点的颜色不是红色就是黑色。
  2. 它的根结点一定是黑色
  3. 它的叶子结点一定是黑色
  4. 如果一个结点的颜色是红色,那么它的左右子结点一定是黑色
  5. 从根结点到叶结点的任一一条路径,黑色结点的数目(黑高)都是相等的。

如下面一棵红黑树:

可以看到,它是符合上面所说的五点性质的,从根结点到每一个叶结点的黑高为3 (为了方便,给红黑树在每一个叶结点加一个空结点,此结点为黑色,这样就满足性质3了)。

为什么要使用红黑树

我们知道,类似C++中的std::map均是使用红黑树做为其实现,我那时候不知道红黑树的时候,就在想这个东西到底有什么好,为什么要用这么个东西来实现?但是我一直想不通,但是今天我觉得用这个实现确实是很好的,比起二叉搜索树来,它要相对平衡一些,考虑插入数据序列「1, 2, 3, 4, 5」如果使用二叉搜索树,结点是这样的:

假设我们要查找元素「5」那么我们必须从「1」开始做比较,然后沿着二叉搜索树,一直比较下来,我们要比较的次数是多少呢?结果应该是n(树的高度),而对于红黑树来说,它的情况是这样的:

这样一来,我们查找的次数,就从5次变成了3次,所以红黑树的查找时间复杂度应该是O(lgn)。所以使用红黑树,查找性能比二叉搜索树要强许多。

那么对于AVL树(平衡二叉查找树)来说,红黑树又有什么优点呢?我们知道对于AVL树,它有一个平衡因子的概念,即:

平衡因子 = |左子树的高度 - 右子树的高度|

相对红黑树来说,可以称AVL树是严格平衡的,但是在增删的时候,需要操作的步骤就比红黑树要多了。即红黑对的操作比AVL树要简单。它并不是彩用平衡因子来衡量树的平衡性,而是引入了黑高。

红黑树结构的定义

红黑树的结构基本与二叉搜索树一致,不过我们增加一个父指针,指向该结点的父结点,便于操作,定义如下:

辅助方法

为了便于观察和操作,定义一些辅助方法,包括输出结点,输出树,删除结点。

输出结点

我们输出结点的地址、结点值、颜色、父结点信息。

输出二叉树

我们以两种方式输出二叉树,一种以深度中序遍历的方式,一种以广度输出的方式。

中序遍历

中序遍历和一般二叉树的中序遍历没有区别,代码如下

广度输出

广度输出是按照树的层次结构来输出的,代码如下

删除结点

删除结点的操作,就是释放掉该指针指向的内存,如下所示

删除红黑树

我们按中序删除整棵红黑树,如下所示:

红黑树的左旋和右旋

在增删结点时,红黑树的性质可能会被破坏,所以我们需要通过调整红黑树来使其重新恢复红黑树的性质。而通常的操作就是通过修改红黑树结点的颜色和旋转操作。

红黑树的旋转:即将红黑树的一个结点向左或向右旋转,且旋转之后仍然符合二叉搜索树的性质。

右旋

右旋的操作有如下步骤:

  1. 将A的左子结点B提升到A的位置
  2. 根据二叉搜索树的性质,A > B,将A变成B的右子结点
  3. 根据二叉搜索树的性质,B < E < A,故将B的右子树E变成A的左子结点,结束

右旋代码如下:

根据代码所示,右旋需要做以下几步操作:

  1. 如果需旋转的结点的左子树为空,那无所谓右旋,因为右旋之后, 空结点将会成为父结点,而空结点代表的本来就是为空,所以这时旋转没有意义
  2. 将左子结点leftNode的结点,指向当前结点node的父指针
  3. 如果node不是根结点,将node的父指针对应的指针指向leftNode
  4. 将node作为leftNode的右子结点,其父指针指向leftNode
  5. leftNode的右子树,变成node的左子树
  6. 如果node是根结点,还需要修改树根指针

左旋

左旋的操作有如下步骤:

  1. 将B的右子结点A提升到B的位置
  2. 根据二叉搜索树的性质,B < A,将B变成A的左子结点
  3. 根据二叉搜索树的性质,B < E < A,故将A的左子树E变成B的右子结点,结束

左旋的代码如下所示:

根据代码所示,左旋需要做以下几个步骤:

  1. 如果需旋转的结点的右子树为空,那无所谓左旋,因为左旋之后, 空结点将会成为父结点,而空结点代表的本来就是为空,所以这时旋转没有意义
  2. 将右子结点rightNode的父指针指向当前结点node的左指针
  3. 如果node不是根结点,将node的父指针指向rightNode
  4. 将node作为rightNode的左子结点,其父指针指向rightNode
  5. rightNode的左子树,变成node的右子树
  6. 如果node是根结点,还要修改树根指针

旋转的示意图如下,左旋和右旋就是一个相互的过程:

红黑树的插入

红黑树的插入和删除是一个麻烦的过程,老实说,我搞了好久,才把插入和删除的过程理清楚,写出正确的程序来。

插入校正

对于结点的插入的修正,我们可以总结为以下几种情况,而且左子树和右子树的处理情况正好相反。我们以z表示插入结点,z.p表示插入结点的父结点,w表示z的叔结点:

  1. z的叔结点w是红色
  2. z的叔结点w是黑色,且z是一个右孩子
  3. z的叔结点w是黑色,且z是一个左孩子

情况一

情况一的示意图如下所示:

此时,很容易想到,为了满足性质,我们可以将「A」点的颜色修改为红色,将「B」「C」点的颜色,修改为黑色,那么此时「A」的左、右子树将分别满足性质。但是此时「A」点的性质可能会遭到破坏,所以z应该指向「A」点,w指针也应该相应的做出修改,如下图所示:

情况二

首先来看z.p是左子结点的情况:

此时,我们只需要对z.p做一次左旋,将z移动到z.p的位置,此时z.p的性质依旧没有恢复,将z修改为z.p,进一步做操作,目前的结果如下所示:

我们发现,此时变成了情况3, 所以可以按情况3再做进一步处理。

再来看z.p是右子结点的情况:

此时,我们可以修改z.p.p的颜色为红色,z.p的颜色修改为黑色,然后进行一次左旋,目前的结果如下所示:

情况三

首先还是先看z.p是左子结点的情况:

此时,我们需要将z.p的颜色修改为黑色,将z.p.p的颜色修改为红色,然后向右旋转一次,如下图所示:

插入示例

下面我以这样一颗树 {11, 2, 28, 1, 5, 22, 30, 20, 17, 18, 19, 24, 23} 来演示一遍插入的全过程。

刚开始,红黑树是一棵空树,然后我们插入「11」作为其根结点,根红黑树的性质,「11」的颜色是黑色。然后我们接着插入结点「2」「28」,如下图:

在这里有一个问题,一开始我们应该选择什么样的颜色进行插入呢,根据红黑树的性质五,根结点到任一叶结点的黑高都相等,此时,如果我们以黑色进行插入,必将破坏性质五,所以每次插入,我们都应该使用红色插入,保证性质五不会被破坏。那么可能被破坏的性质就只有性质二和性质和性质四。

为什么性质三不会被破坏呢?在前面,我们已经加入了一个空结点,作为哨兵的做用,也是所有叶结点的子结点,此结点的颜色为黑色,所以性质三一定是成立的。

接下来,我们继续插入「1」

此时,可以看到插入「1」之后,红黑树的性质四被破坏了,那么怎么样才能恢复性质四呢?不难想到,我们可以将「11」变成红色,将「2」「28」变成黑色,这样既恢复了性质四,但由于「11」是根结点,这样又违反了性质二,所以,将「11」再调整为黑色,即可恢复红黑树的性质,这样树就变成了下面这样:

可以看到,现在每条路径的黑高,均为「3」接着继续插入结点「1」「5」「22」「30」,这几个结点的插入没有引起红黑树的破坏。

接下来,我们插入结点「20」同样,插入之后,会破坏性质四,于是,我们将「28」的颜色调整为红色,将「22」「30」的颜色调整为黑色,结果如下:

然后继续插入「17」,插入之后,树将会变成这样:

性质四继续被破坏,但是此时,首先,我们将「22」变为红色,将「20」变成黑色,这样「22」的左子树便符合了红黑树的性质,如下图所示:

但是此时「28」的性质被破坏,因为它的左子结点「22」是红色,而且此时,我们无法通过修改颜色来使其恢复性质(如果修改颜色,从「28」到「17」的黑高为 3, 而从「28」到「22」的右子树的黑高为 2)

此时,我们只能通过旋转的方式来使其恢复性质,不难想到,很明显,「22」的平衡因子为 2, 因此,我们应该向右旋,使其尽量保持平衡。然后使「22」变为红色,「20」变为黑色,使其恢复性质,如下图:

接着,我们再插入「18」,「18」应为「17」的右子树,根据前面所述,我们需要将「20」的颜色变成红色,再将「17」「22」的颜色变成黑色,如下图所示:

此时结点「20」的性质被破坏,由于「28」的平衡因子为 2 ,所以,我们应该以「28」为中点,向右进行旋转,如下图所示:

此时,「28」仍不满足性质,于是,我们将「11」的颜色修改成红色,「20」修改为黑色,然后向左旋转:

然后再插入结点「19」,插入之后,同样的,我们将「17」的颜色修改为红色,将「18」的颜色修改为黑色,然后向左旋转,即可满足性质,如下所示:

最终,我们插入「24」「23」插入「24」并不破坏性质,但是插入「23」的时候,这样处理,首先,以「24」为中心点进行一次右旋,然后将「23」修改为黑色,「22」修改为红色,以「22」为根结点,向左旋转即可恢复性质,最终结果如下图所示:

至此,所有结点插入完毕。首先请看插入结点的代码,但是在插入结点之前,我们首先要编写建立结点的代码,如下所示:

我们首先建立结点,将并将颜色值设置为红色,如果此时哨兵结点为空,则建立哨兵结点,然后将当前结点的左指针、右指针、父指针指向该结点。然后开始插入结点,代码如下所示:

从代码中可以看到,我们插入一个结点p,需要执行以下几个步骤

  1. 首先查找合适的投放位置q
  2. 找到之后,我们将需要p的父指针指向q
  3. 将q对应的左右指针指向p
  4. 如果当前结点是根结点,则将树根结点指向p
  5. 插入之后,可能破坏红黑树的性质,所以需要调用insert_fixup进行校正

下面请看校正的代码:


根据上述所说,以上代码便十分好理解。在此就不多废话了。

红黑树的删除

其实老实说起来,红黑树结点的插入还算是简单,但是删除过程,比插入更加麻烦,我搞了很久,就是卡在这里。搞了好久才搞清楚整个过程。下面我将分情况一一进行说明。

对于红黑树的删除来说,当我们删除这一点的时候,我们需要找一点来作为替代。我们找的点,应该是使改动尽可能的小,所以我们分三种情况来寻找替代

  1. 当删除点的左子树为空的时候,我们使用删除结点的右子结点做为替代
  2. 同样,当删除点的右子树为这的时候,我们使用删除结点的左子结点做为替代
  3. 若左右子树均不为空,为了使变动最小,我们就使用该子结点的后继做为替代。

所以我们在删除结点之前,先编写查找后继的代码,很简单,如下:

然后我们开始编写删除结点的方法,如下所示:

第一个删除方法:

第二个删除方法:

我们看第二个删除结点的函数,我们定义x指向删除处的结点,需要进行以下几种情况:

  1. 首先,如果左子树为空,我们就用右子树做替代,调整父指针,使用x指向删除的结点
  2. 其次,如果右子树为空,同样以左子树做替代,调整父指针,使用x指向删除的结点
  3. 当左右子树不为空的时候,我们首先查找后继,使用后继续替换删除结点的位置,将后继结点的颜色修改为删除结点的颜色
  4. 此时,就相当于把是删除后继结点,使用x指向该结点
  5. 如果删除的节点是红色的,那么我们不需要做什么改动,因为删除红色不会影响红黑树的性质
  6. 如果删除的节点是黑色的,那么我们就需要对红黑树做校正,以使其恢复

删除校正

只有当删除的结点是黑色的时候,我们才需要做校正,删除校正我们需要分成以下几种情况下讨论:

  1. x的兄弟结点w是红色的
  2. x的兄弟结点w是黑色的,且w的两个子结点都是黑色
  3. x的兄弟结点w是黑色,且w的左孩子是红色,w的右孩子是黑色
  4. x的兄弟结点w是黑色,且w的右孩子是红色

情况一

首先看左子树,「d」表示要删除的点,如下图所示:

此时,删除结点之后,我们将「E」结点的颜色修改为红色,「I」结点的颜色修改为黑色,然后向左旋转,结果如下所示:

那么再看右子树的情况,一样的,我们只需要将w的颜色修改为黑色,将w.p的颜色修改为红色,然后向右旋转,结果如下所示:

情况二

这种情况的与左、右子结点无关,「x」表示删除结点之后,如图所示:

此时,我们只需要将x的兄弟结点变成红色结点,之后父结点的性质可能会遭到破坏,所以x应该指向x的父结点。

情况三

先看左子结点的情况,如下图所示:

此时,我们需要将w的颜色修改为红色,然后将w的左子结点修改为黑色,然后向右旋转一次,如下图所示:

再来看看右子树的情况,如下图所示:

此时,我们需要将「C」结点的颜色修改为红色,「G」结点的颜色修改为黑色,然后左旋一次,如下图所示:

情况四

照样先看左子树的情况,如下图所示:

此时,我们将「C」结点的元素替换为「A」结点的颜色,然后将「G」结点的右子结点的颜色修改为黑色,然后向左旋转一次,并将x点修改为根结点,如下图所示:

再看右子树的情况,如下图所示:

此时,我们需要将「C」结点的颜色替换成「A」结点的颜色,然后将「F」点的颜色修改为黑色,然后右旋一次,再将x指向根结点,如下图所示:

下面请看代码,如下所示是删除的校正代码:



下面我们以一棵树,从开始插入结点,到最后删除全部结点来做示例:如下所示:

代码输出

输出如下所示,为了表示分隔,我加了一条线,最终的输出如下:




结束

上述阐述可能并不完全正确,代码也可能尚有错误,但代码也是我经过这么长时间辛苦写出来的,也没什么参考,请各位大侠勿喷,下面是全部的代码:

//
//  main.cpp
//  RBTee
//
//  Created by 王落凡 on 2017/5/2.
//  Copyright © 2017年. All rights reserved.
//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef enum {RBTreeNodeColorRed, RBTreeNodeColorBlack} RBTreeNodeColor;

typedef struct RBTreeNode {
    int element;                                        //元素值
    RBTreeNodeColor nodeColor;                          //结点颜色
    struct RBTreeNode* leftChild;                       //左子树
    struct RBTreeNode* rightChild;                      //右子树
    struct RBTreeNode* parentPtr;                       //父结点

}RBTreeNode;

struct RBTreeNode* nilNode = nullptr;

inline void safe_delete(void* ptr)
{
    if(ptr != nullptr) {
        free(ptr);
        ptr = nullptr;
    }
    return ;
}

struct RBTreeNode* initNode(int elem)
{
    struct RBTreeNode* node = (struct RBTreeNode*)malloc(sizeof(struct RBTreeNode));

    node->element = elem;
    node->parentPtr = nullptr;
    node->nodeColor = RBTreeNodeColorRed;
    node->leftChild = nullptr;
    node->rightChild = nullptr;

    if(nilNode == nullptr)
    {
        nilNode = (struct RBTreeNode*)malloc(sizeof(struct RBTreeNode));
        nilNode->element = 0;
        nilNode->parentPtr = nullptr;
        nilNode->nodeColor = RBTreeNodeColorBlack;
        nilNode->leftChild = nullptr;
        nilNode->rightChild = nullptr;
    }

    node->leftChild = nilNode;
    node->rightChild = nilNode;
    node->parentPtr = nilNode;
    return node;
}

inline void printNode(struct RBTreeNode* node)
{
    if(node == nullptr)
        return ;

    printf("Node: %p Elem: %d, Color: %s, Parent: %p, ParentElem: %d\n",node, node->element, node->nodeColor == RBTreeNodeColorRed ? "Red" : "Black", node->parentPtr, node->parentPtr->element);
    return ;
}

void printTree(struct RBTreeNode* RBTree, size_t height)
{
    if(RBTree == nullptr)
        return ;

    //构建队列
    struct RBTreeNode** queue = (struct RBTreeNode**)malloc(sizeof(struct RBTreeNode*) * height);
    memset(queue, 0, height * sizeof(struct RBTreeNode*));
    int beg = 0, end = 0;

    //树根入队
    queue[end++] = RBTree;

    while(beg < end)
    {
        struct RBTreeNode* node = queue[beg++];

        if(node == nullptr)
            return ;

        if(node) printNode(node);
        if(node->leftChild != nilNode) queue[end++] = node->leftChild;
        if(node->rightChild != nilNode) queue[end++] = node->rightChild;
    }

    safe_delete(queue);
    return ;
}

void printTreeInOrder(struct RBTreeNode* RBTree)
{
    if(RBTree == nullptr)
        return ;

    if(RBTree->leftChild != nilNode)
        printTreeInOrder(RBTree->leftChild);
    printNode(RBTree);
    if(RBTree->rightChild != nilNode)
        printTreeInOrder(RBTree->rightChild);
    return ;
}

void rightRotate(struct RBTreeNode*& RBTree, struct RBTreeNode* node)
{
    if(node->leftChild == nilNode)
        return ;

    struct RBTreeNode* parentNode = node->parentPtr;
    struct RBTreeNode* leftNode = node->leftChild;

    leftNode->parentPtr = parentNode;
    node->parentPtr = leftNode;

    leftNode->rightChild->parentPtr = node;

    if(leftNode->parentPtr != nilNode)
    {
        if(parentNode->leftChild == node)
            parentNode->leftChild = leftNode;
        else
            parentNode->rightChild = leftNode;
    }

    node->leftChild = leftNode->rightChild;
    leftNode->rightChild = node;

    if(leftNode->parentPtr == nilNode)
        RBTree = leftNode;

    return ;
}

void leftRotate(struct RBTreeNode*& RBTree, struct RBTreeNode* node)
{
    if(node->rightChild == nilNode)
        return ;

    struct RBTreeNode* parentNode = node->parentPtr;
    struct RBTreeNode* rightNode = node->rightChild;

    rightNode->parentPtr = parentNode;

    rightNode->leftChild->parentPtr = node;
    node->rightChild = rightNode->leftChild;

    if(node != RBTree)
    {
        if(parentNode->leftChild == node)
            parentNode->leftChild = rightNode;
        else
            parentNode->rightChild = rightNode;
    }

    node->parentPtr = rightNode;
    rightNode->leftChild = node;

    if(rightNode->parentPtr == nilNode)
        RBTree = rightNode;

    return ;
}

void insert_fixup(struct RBTreeNode*& RBTree, struct RBTreeNode* node)
{
    struct RBTreeNode* z = node;
    while(z != nilNode && z->parentPtr->nodeColor == RBTreeNodeColorRed && z->parentPtr != nilNode)
    {
        if(z->parentPtr->parentPtr->leftChild == z->parentPtr)
        {
            if(z->parentPtr->parentPtr->rightChild->nodeColor == RBTreeNodeColorRed)
            {
                z->parentPtr->parentPtr->nodeColor = RBTreeNodeColorRed;
                z->parentPtr->nodeColor = RBTreeNodeColorBlack;
                z->parentPtr->parentPtr->rightChild->nodeColor = RBTreeNodeColorBlack;

                z = z->parentPtr->parentPtr;
            }
            else
            {
                if(z->parentPtr->rightChild == z)
                {
                    z = z->parentPtr;
                    leftRotate(RBTree, z);
                }
                else
                {
                    z->parentPtr->nodeColor = RBTreeNodeColorBlack;
                    z->parentPtr->parentPtr->nodeColor = RBTreeNodeColorRed;

                    rightRotate(RBTree, z->parentPtr->parentPtr);
                }
            }
        }
        else
        {
            if(z->parentPtr->parentPtr->leftChild->nodeColor == RBTreeNodeColorRed)
            {
                z->parentPtr->parentPtr->nodeColor = RBTreeNodeColorRed;
                z->parentPtr->nodeColor = RBTreeNodeColorBlack;
                z->parentPtr->parentPtr->leftChild->nodeColor = RBTreeNodeColorBlack;

                z = z->parentPtr->parentPtr;
            }else
            {
                if(z->parentPtr->leftChild == z)
                {
                    z = z->parentPtr;
                    rightRotate(RBTree, z);
                }
                else
                {
                    z->parentPtr->nodeColor = RBTreeNodeColorBlack;
                    z->parentPtr->parentPtr->nodeColor = RBTreeNodeColorRed;

                    leftRotate(RBTree, z->parentPtr->parentPtr);
                }
            }
        }
    }

    //将根结点修改为黑色
    RBTree->nodeColor = RBTreeNodeColorBlack;
    return ;
}

void insertNode(struct RBTreeNode*& RBTree, int elem)
{
    struct RBTreeNode* p = initNode(elem), *q = RBTree;

    while(q)
    {
        if(q->element > p->element)
        {
            if(q->leftChild != nilNode)
                q = q->leftChild;
            else
            {
                q->leftChild = p;
                p->parentPtr = q;
                break;
            }
        }
        else
        {
            if(q->rightChild != nilNode)
                q = q->rightChild;
            else
            {
                q->rightChild = p;
                p->parentPtr = q;
                break;
            }
        }
    }

    if(RBTree == nullptr)
    {
        RBTree = p;
        RBTree->nodeColor = RBTreeNodeColorBlack;
        return ;
    }

    insert_fixup(RBTree, p);
    return ;
}

inline struct RBTreeNode* prior(struct RBTreeNode* node)
{
    if(node->rightChild == nilNode)
        return nilNode;

    struct RBTreeNode* p = node->rightChild;
    while(p->leftChild != nilNode) p = p->leftChild;

    return p;
}

struct RBTreeNode* findNodeByElement(struct RBTreeNode* RBTree, int elem)
{
    struct RBTreeNode* p = RBTree;
    if(p == nullptr)
        return nullptr;

    if(p->element == elem)
        return p;
    else if(p->element > elem)
        return findNodeByElement(RBTree->leftChild, elem);
    else
        return findNodeByElement(RBTree->rightChild, elem);

    return p;
}

void delete_fixup(struct RBTreeNode*& RBTree, struct RBTreeNode* node)
{
    struct RBTreeNode* x = node;
    struct RBTreeNode* p = node->parentPtr;

    while(x != RBTree && x->nodeColor == RBTreeNodeColorBlack)
    {
        if(p->leftChild == x)
        {
            struct RBTreeNode* w = p->rightChild;

            if(w->nodeColor == RBTreeNodeColorRed)
            {
                //情况1:x的兄弟结点w是红色
                p->nodeColor = RBTreeNodeColorRed;
                w->nodeColor = RBTreeNodeColorBlack;

                leftRotate(RBTree, p);
                x = p->leftChild;
            }
            else
            {
                if(w->leftChild->nodeColor == RBTreeNodeColorBlack && w->rightChild->nodeColor == RBTreeNodeColorBlack)
                {
                    //情况2:x的兄弟结点是黑色,且两侄结点全是黑色
                    w->nodeColor = RBTreeNodeColorRed;
                    x = p;
                }
                else if(w->leftChild->nodeColor == RBTreeNodeColorRed && w->rightChild->nodeColor == RBTreeNodeColorBlack)
                {
                    //情况3:x的兄弟结点w是黑色,且w的左孩子是红色,右孩子是黑色
                    w->nodeColor = RBTreeNodeColorRed;
                    w->leftChild->nodeColor = RBTreeNodeColorBlack;

                    rightRotate(RBTree, w);
                }
                else
                {
                    //情况4:x的兄弟结点w是黑色,且w的右孩子是红色
                    w->nodeColor = p->nodeColor;
                    w->rightChild->nodeColor = RBTreeNodeColorBlack;
                    p->nodeColor = RBTreeNodeColorBlack;

                    leftRotate(RBTree, p);

                    x = RBTree;
                }
            }
        }
        else
        {
            struct RBTreeNode* w = p->leftChild;

            if(w->nodeColor == RBTreeNodeColorRed)
            {
                //情况1:x的兄弟结点w是红色
                p->nodeColor = RBTreeNodeColorRed;
                w->nodeColor = RBTreeNodeColorBlack;

                rightRotate(RBTree, p);
                x = p->rightChild;
            }
            else
            {
                if(w->rightChild->nodeColor == RBTreeNodeColorBlack && w->leftChild->nodeColor == RBTreeNodeColorBlack)
                {
                    //情况2:x的兄弟结点是黑色,且两侄结点全是黑色
                    w->nodeColor = RBTreeNodeColorRed;
                    x = p;
                }
                else if(w->rightChild->nodeColor == RBTreeNodeColorRed && w->leftChild->nodeColor == RBTreeNodeColorBlack)
                {
                    //情况3:x的兄弟结点w是黑色,且w的右孩子是红色,左孩子是黑色
                    w->nodeColor = RBTreeNodeColorRed;
                    w->rightChild->nodeColor = RBTreeNodeColorBlack;

                    leftRotate(RBTree, w);
                }
                else
                {
                    //情况4:x的兄弟结点w是黑色,且w的左孩子是红色
                    w->nodeColor = p->nodeColor;
                    w->leftChild->nodeColor = RBTreeNodeColorBlack;
                    p->nodeColor = RBTreeNodeColorBlack;

                    rightRotate(RBTree, p);

                    x = RBTree;
                }
            }
        }
    }

    x->nodeColor = RBTreeNodeColorBlack;
    return ;
}

void deleteNode(struct RBTreeNode*& RBTree, struct RBTreeNode* node)
{
    RBTreeNodeColor nodeColor = node->nodeColor;
    struct RBTreeNode* x = nilNode;

    if(node->leftChild == nilNode)
    {
        x = node->rightChild;

        node->rightChild->parentPtr = node->parentPtr;
        if(node == RBTree)
            RBTree = node->rightChild;
        else if(node->parentPtr->leftChild == node)
            node->parentPtr->leftChild = node->rightChild;
        else
            node->parentPtr->rightChild = node->rightChild;
    }
    else if(node->rightChild == nilNode)
    {
        x = node->leftChild;

        node->leftChild->parentPtr = node->parentPtr;
        if(node == RBTree)
            RBTree = node->leftChild;
        else if(node->parentPtr->leftChild == node)
            node->parentPtr->leftChild = node->leftChild;
        else
            node->parentPtr->rightChild = node->leftChild;
    }
    else
    {
        struct RBTreeNode* p = prior(node);
        nodeColor = p->nodeColor;
        p->nodeColor = node->nodeColor;

        if(p->parentPtr == node)
        {
            x = p->rightChild;

            p->parentPtr = node->parentPtr;
            node->leftChild->parentPtr = p;
            p->leftChild = node->leftChild;

            x->parentPtr = p;
        }
        else
        {
            x = p->rightChild;

            p->rightChild->parentPtr = p->parentPtr;
            p->parentPtr->leftChild = p->rightChild;
            node->leftChild->parentPtr = p;
            node->rightChild->parentPtr = p;
            p->leftChild = node->leftChild;
            p->rightChild = node->rightChild;
            p->parentPtr = node->parentPtr;
        }

        if(node == RBTree)
            RBTree = p;
        else if(node->parentPtr->leftChild == node)
            node->parentPtr->leftChild = p;
        else
            node->parentPtr->rightChild = p;
    }

    safe_delete(node);
    if(nodeColor == RBTreeNodeColorBlack)
        delete_fixup(RBTree, x);
    return ;
}

void deleteNode(struct RBTreeNode*& RBTree, int elem)
{
    struct RBTreeNode* node = findNodeByElement(RBTree, elem);
    if(node)
        deleteNode(RBTree, node);
    return ;
}

void destroyRBTree(struct RBTreeNode*& RBTree)
{
    if(RBTree == nullptr)
        return ;

    if(RBTree->leftChild != nilNode)
        destroyRBTree(RBTree->leftChild);
    if(RBTree->rightChild != nilNode)
        destroyRBTree(RBTree->rightChild);

    RBTree->leftChild = nullptr;
    RBTree->rightChild = nullptr;
    RBTree->parentPtr = nullptr;

    safe_delete(RBTree);

    return ;
}

int main(int argc, const char * argv[])
{
    //    int nums[] = {11, 2, 14, 1, 7, 15, 5, 8 , 4};
    int nums[] = {11, 2, 28, 1, 5, 22, 30, 20, 17, 18, 19, 24, 23};
    struct RBTreeNode* RBTree = nullptr;


    printf("插入结点\n");
    for(int i = 0 ; i < sizeof(nums) / sizeof(int); ++i)
    {
        insertNode(RBTree, nums[i]);
        printTree(RBTree, sizeof(nums) / sizeof(int));
        printf("-----------------------------------------------\n");
    }

    printf("删除结点\n");
    for(int i = 0; i != sizeof(nums) / sizeof(int); ++i)
    {
        deleteNode(RBTree, nums[i]);
        printTree(RBTree, sizeof(nums) / sizeof(int));
        printf("-----------------------------------------------\n");
    }

    destroyRBTree(RBTree);
    return 0;
}

麻痹,优快云出了问题,这篇文章被搞没了,还好有个百度快照又给搞回来了,真TM操蛋。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值