红黑树真TM是一个非常难的数据结构,至少对我这种非计算机专业的业余爱好者来说是非常难的,正好这段时间想学学这个,虽然中间断断续续的学了一点点,但是都没有彻底的去熟悉甚至去实现这样一棵红黑树,直到今天,才真正的实现了一棵红黑树。为了使自己所学的东西更加的巩固,于是决定不自量力,写篇博客,若有错漏,请指出,勿喷,毕竟本人只是一个非专业型娱乐辣鸡选手。
什么是红黑树
红黑树是什么?之前我曾经写过一篇关于二叉搜索树的博客,红黑树其实就是一棵非严格平衡的二叉搜索树,它有以下五点性质:
- 它所有结点的颜色不是红色就是黑色。
- 它的根结点一定是黑色
- 它的叶子结点一定是黑色
- 如果一个结点的颜色是红色,那么它的左右子结点一定是黑色
- 从根结点到叶结点的任一一条路径,黑色结点的数目(黑高)都是相等的。
如下面一棵红黑树:
可以看到,它是符合上面所说的五点性质的,从根结点到每一个叶结点的黑高为3 (为了方便,给红黑树在每一个叶结点加一个空结点,此结点为黑色,这样就满足性质3了)。
为什么要使用红黑树
我们知道,类似C++中的std::map均是使用红黑树做为其实现,我那时候不知道红黑树的时候,就在想这个东西到底有什么好,为什么要用这么个东西来实现?但是我一直想不通,但是今天我觉得用这个实现确实是很好的,比起二叉搜索树来,它要相对平衡一些,考虑插入数据序列「1, 2, 3, 4, 5」如果使用二叉搜索树,结点是这样的:
假设我们要查找元素「5」那么我们必须从「1」开始做比较,然后沿着二叉搜索树,一直比较下来,我们要比较的次数是多少呢?结果应该是n(树的高度),而对于红黑树来说,它的情况是这样的:
这样一来,我们查找的次数,就从5次变成了3次,所以红黑树的查找时间复杂度应该是O(lgn)。所以使用红黑树,查找性能比二叉搜索树要强许多。
那么对于AVL树(平衡二叉查找树)来说,红黑树又有什么优点呢?我们知道对于AVL树,它有一个平衡因子的概念,即:
平衡因子 = |左子树的高度 - 右子树的高度|
相对红黑树来说,可以称AVL树是严格平衡的,但是在增删的时候,需要操作的步骤就比红黑树要多了。即红黑对的操作比AVL树要简单。它并不是彩用平衡因子来衡量树的平衡性,而是引入了黑高。
红黑树结构的定义
红黑树的结构基本与二叉搜索树一致,不过我们增加一个父指针,指向该结点的父结点,便于操作,定义如下:
辅助方法
为了便于观察和操作,定义一些辅助方法,包括输出结点,输出树,删除结点。
输出结点
我们输出结点的地址、结点值、颜色、父结点信息。
输出二叉树
我们以两种方式输出二叉树,一种以深度中序遍历的方式,一种以广度输出的方式。
中序遍历
中序遍历和一般二叉树的中序遍历没有区别,代码如下
广度输出
广度输出是按照树的层次结构来输出的,代码如下
删除结点
删除结点的操作,就是释放掉该指针指向的内存,如下所示
删除红黑树
我们按中序删除整棵红黑树,如下所示:
红黑树的左旋和右旋
在增删结点时,红黑树的性质可能会被破坏,所以我们需要通过调整红黑树来使其重新恢复红黑树的性质。而通常的操作就是通过修改红黑树结点的颜色和旋转操作。
红黑树的旋转:即将红黑树的一个结点向左或向右旋转,且旋转之后仍然符合二叉搜索树的性质。
右旋
右旋的操作有如下步骤:
- 将A的左子结点B提升到A的位置
- 根据二叉搜索树的性质,A > B,将A变成B的右子结点
- 根据二叉搜索树的性质,B < E < A,故将B的右子树E变成A的左子结点,结束
右旋代码如下:
根据代码所示,右旋需要做以下几步操作:
- 如果需旋转的结点的左子树为空,那无所谓右旋,因为右旋之后, 空结点将会成为父结点,而空结点代表的本来就是为空,所以这时旋转没有意义
- 将左子结点leftNode的结点,指向当前结点node的父指针
- 如果node不是根结点,将node的父指针对应的指针指向leftNode
- 将node作为leftNode的右子结点,其父指针指向leftNode
- leftNode的右子树,变成node的左子树
- 如果node是根结点,还需要修改树根指针
左旋
左旋的操作有如下步骤:
- 将B的右子结点A提升到B的位置
- 根据二叉搜索树的性质,B < A,将B变成A的左子结点
- 根据二叉搜索树的性质,B < E < A,故将A的左子树E变成B的右子结点,结束
左旋的代码如下所示:
根据代码所示,左旋需要做以下几个步骤:
- 如果需旋转的结点的右子树为空,那无所谓左旋,因为左旋之后, 空结点将会成为父结点,而空结点代表的本来就是为空,所以这时旋转没有意义
- 将右子结点rightNode的父指针指向当前结点node的左指针
- 如果node不是根结点,将node的父指针指向rightNode
- 将node作为rightNode的左子结点,其父指针指向rightNode
- rightNode的左子树,变成node的右子树
- 如果node是根结点,还要修改树根指针
旋转的示意图如下,左旋和右旋就是一个相互的过程:
红黑树的插入
红黑树的插入和删除是一个麻烦的过程,老实说,我搞了好久,才把插入和删除的过程理清楚,写出正确的程序来。
插入校正
对于结点的插入的修正,我们可以总结为以下几种情况,而且左子树和右子树的处理情况正好相反。我们以z表示插入结点,z.p表示插入结点的父结点,w表示z的叔结点:
- z的叔结点w是红色
- z的叔结点w是黑色,且z是一个右孩子
- 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,需要执行以下几个步骤
- 首先查找合适的投放位置q
- 找到之后,我们将需要p的父指针指向q
- 将q对应的左右指针指向p
- 如果当前结点是根结点,则将树根结点指向p
- 插入之后,可能破坏红黑树的性质,所以需要调用insert_fixup进行校正
下面请看校正的代码:
根据上述所说,以上代码便十分好理解。在此就不多废话了。
红黑树的删除
其实老实说起来,红黑树结点的插入还算是简单,但是删除过程,比插入更加麻烦,我搞了很久,就是卡在这里。搞了好久才搞清楚整个过程。下面我将分情况一一进行说明。
对于红黑树的删除来说,当我们删除这一点的时候,我们需要找一点来作为替代。我们找的点,应该是使改动尽可能的小,所以我们分三种情况来寻找替代
- 当删除点的左子树为空的时候,我们使用删除结点的右子结点做为替代
- 同样,当删除点的右子树为这的时候,我们使用删除结点的左子结点做为替代
- 若左右子树均不为空,为了使变动最小,我们就使用该子结点的后继做为替代。
所以我们在删除结点之前,先编写查找后继的代码,很简单,如下:
然后我们开始编写删除结点的方法,如下所示:
第一个删除方法:
第二个删除方法:
我们看第二个删除结点的函数,我们定义x指向删除处的结点,需要进行以下几种情况:
- 首先,如果左子树为空,我们就用右子树做替代,调整父指针,使用x指向删除的结点
- 其次,如果右子树为空,同样以左子树做替代,调整父指针,使用x指向删除的结点
- 当左右子树不为空的时候,我们首先查找后继,使用后继续替换删除结点的位置,将后继结点的颜色修改为删除结点的颜色
- 此时,就相当于把是删除后继结点,使用x指向该结点
- 如果删除的节点是红色的,那么我们不需要做什么改动,因为删除红色不会影响红黑树的性质
- 如果删除的节点是黑色的,那么我们就需要对红黑树做校正,以使其恢复
删除校正
只有当删除的结点是黑色的时候,我们才需要做校正,删除校正我们需要分成以下几种情况下讨论:
- x的兄弟结点w是红色的
- x的兄弟结点w是黑色的,且w的两个子结点都是黑色
- x的兄弟结点w是黑色,且w的左孩子是红色,w的右孩子是黑色
- 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操蛋。