您的位置:首页 > 编程语言 > C语言/C++

红黑树C++源码, 有详细注释

2013-05-31 21:22 267 查看
/*tc                                       c                 !(
wdULCC4w7  ?5                       r?        Tw.    's"        Va
-dj     bJ  ob                       f4        `Gg-  lDS'       `kO
)b,    ub-  jw   ?a847  `C8S2'  ?s88CxL:J    ui -Gxlxwo  ,L8Sv- 'F5      joo8Tl.;:   j44aj )sC083
"D-    nd;  jw  jD2rIOf!hf1ioG1jbCrioxL)bs  LD)   Gdz-  (g0rc3P:-m5      O61iowwfxU'LyvICq5*NTvi;
:b-     aG  jw  S9   "RlF!   98ST    Us   8uX*    4a    IR    be Kn      5x   (? -plywYa8hz,Fi
:y- Cfnngu  lb  ?g8njU5-sge326)7D4CLYGa    R:     8S    'V6noLf,.K6222Cz`5G      ?q(zda5l  `yn
-*  'jnnr   (I   -Jei.   iuJ(   !znCri?  zD?      ;7      jet,  `IzCCCCz`"1      (j  *znc   7"
t*/

/*` `.;:
!. .;//))//'        ~:                      ´`      `´            !=\>>\««"/
_"»=«]=^~-7:        -[,         _>          <"      .=!           _3`  '%.
,=;                   -2_!%%*>´'='         \*-}«. !_' >4-^^       ,['      »)           _*    =^ ^{{.
.(=_                     ?( <64( "}      _77»"3<(<<%«]>:%+&3)        =-   «~ {*_/-        _>`,_{=>}»%%^
.?32;    `_((/\».          -%^^$?,*\       .^^')+  ._7.<+>){*'     ': ´»,   ;+/»$»*-        _2[+&&%{.´
`!.~»(  ^7?(^&<.           ´%6$2$5\            /%    :]].´` /      '7,_4(    ´-<%           >«!´<«*<+&%
\} .1_   *`            /11»<?:             /&- !´ &0`:1*>       \\ ($_     ("~,         *>  ^$7>~;]
.»6.´*:   (»             ´{;<=3{             +4&[=~\%+1 !1[´      (\ `!?,  (737%3`        "\   3!_(^7
!1?*}<( `,<67\\/}.        .*%307´ `´         '6"!:.-2!`\´ `7,      ;>´( `´  ,-<1%;         ?/  `3!>?}1
`. ,7< ^%%»\/())«*`       '«\"3[<(*}         (&*   `'     ´<       ``.<      `%=!         `?!  `3-7;«»
)4. ´.`       `        '»»?=>/.´  :.     '7?"          '<         .<    ')=)           .1´  `[)3}[;
=«                  ^    ^_` }»`  ]}     ~7$=        `´´<         ;«   ~«7«()//)´      ~7`  `%11\2.
4000

,['                  ="'  :?}`':` ~&^      `3=        ´<'<         /?       `````       »«    <1~=[!
!;                   `-´          "}        ´.         }7»         /*                  !2:  ~/[^  :"<´
`                     =>         »"                  ~?   ^\^    `"*/
///> 1. 每个结点要么是红的,要么是黑的。
///> 2. 根结点是黑的。
///> 3. 每个叶结点,即空结点(NIL)是黑的。
///> 4. 如果一个结点是红的,那么它的俩个儿子都是黑的。
///> 5. 对每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点。

#include <iostream>
#include <ctime>

enum COLOR
{
black = 0,
red   = 1,
};

struct RBNode
{
COLOR color;
RBNode* pParent;
RBNode* pLeft;
RBNode* pRight;
int val;

RBNode(int nVal = 0)
: color(red)
, pLeft(NULL)
, pRight(NULL)
, pParent(NULL)
, val(nVal)
{
}

RBNode(RBNode* left, RBNode* right, RBNode* parent, int nVal, COLOR enumColor = red)
: color(enumColor)
, pLeft(left)
, pRight(right)
, pParent(parent)
, val(nVal)
{
}
};

class RBTree
{
public:
RBTree();
~RBTree();

public:
bool Insert(int keyVal);
bool DeleteNode(int keyVal);
void DisplayNode();
int GetNodeSize() const;
RBNode* TreeFind(int keyVal);
void DisplayTree();
int GetSize();

private:
RBNode* _SearchNode(int keyVal);
RBNode* _MinimumNode(int kevVal);
RBNode* _MaximumNode(int kevVal);
RBNode* _MinimumNode(RBNode* pNode);
RBNode* _MaximumNode(RBNode* pNode);
RBNode* _SuccessorNode(int keyVal);
RBNode* _SuccessorNode(RBNode* pNode);
RBNode* _SearchNode(RBNode* pNode, int keyVal);
void _InsertFixedUp(RBNode* pNode);
///> _InsertFixedUp2和上面的运算结果一样的, 虽然代码不一样
void _InsertFixedUp2(RBNode* pNode);
void _DelFixedUp(RBNode* pNode);
bool _LeftRotate(RBNode* pNode);
bool _RightRotate(RBNode* pNode);
void _DisplayTree(RBNode* pNode);

private:
RBNode* m_root;
RBNode* m_Nil;
int m_size;
};

RBTree::RBTree()
{
m_root = m_Nil;
m_Nil = new RBNode(0x0fffffff);
m_Nil->color = black;
m_size = 0;
}

RBTree::~RBTree()
{
if(m_root != m_Nil && m_root != NULL){
delete m_root;
m_root = NULL;
}
if(m_Nil != NULL){
delete m_Nil;
m_Nil = NULL;
}
}

bool RBTree::_LeftRotate(RBNode* pNode)
{
if(pNode == m_Nil || pNode->pRight == m_Nil)
{
return false;
}

RBNode* pRightChild = pNode->pRight;
///> 此时右孩子parent指针已指向了node的父节点
pRightChild->pParent = pNode->pParent;
///> 所谓左旋就是右孩子的左节点成为node的右结点
pNode->pRight = pRightChild->pLeft;

if(pRightChild->pLeft != m_Nil)
{
///> 所谓左旋就是右孩子的左节点成为node的右结点
pRightChild->pLeft->pParent = pNode;
}

///> 如果node就是root节点
if(pNode->pParent == m_Nil)
{
///>··则让root节点为pRightChild
m_root = pRightChild;
m_Nil->pLeft = m_root;
m_Nil->pRight = m_root;
}
///> 如果node不是root节点
else
{
///> 如果位于右边
if(pNode == pNode->pParent->pLeft)
{
///> 则让node的父节点把指向node的指针改为
///> 指向pRightChild
pNode->pParent->pLeft = pRightChild;
}
///> 反之······
else
{
pNode->pParent->pRight = pRightChild;
}
}

///> 所谓左旋就是右孩子的左节点成为node的右结点
///> node的父节点把指向node的指针改为指向pRightChild
///> 并且node成为自己右孩子的孩子
pNode->pParent = pRightChild;
pRightChild->pLeft = pNode;

return true;
}

bool RBTree::_RightRotate(RBNode* pNode)
{
if(pNode == m_Nil || pNode->pLeft == m_Nil)
{
return false;
}

RBNode* pLeftChild = pNode->pLeft;
pNode->pLeft = pLeftChild->pRight;
pLeftChild->pParent = pNode->pParent;

if(pLeftChild->pRight != m_Nil)
{
pLeftChild->pRight->pParent = pNode;
}

if(pNode->pParent == m_Nil)
{
m_root = pLeftChild;
m_Nil->pLeft = m_root;
m_Nil->pRight = m_root;
}
else
{
if(pNode == pNode->pParent->pRight)
{
pNode->pParent->pRight = pLeftChild;
}
else
{
pNode->pParent->pLeft = pLeftChild;
}
}

pNode->pParent = pLeftChild;
pLeftChild->pRight = pNode;

return true;
}

RBNode* RBTree::TreeFind(int keyVal)
{
RBNode* pNode = _SearchNode(keyVal);
if(pNode == m_Nil)
{
///> 作为对外接口则返回NULL而不是m_Nil
return NULL;
}

return pNode;
}

RBNode* RBTree::_SearchNode(int keyVal)
{
RBNode* pNode = _SearchNode(m_root, keyVal);

return pNode;
}

RBNode* RBTree::_SearchNode(RBNode* pNode, int keyVal)
{
if(pNode == m_Nil || keyVal == pNode->val)
{
return pNode;
}

if(keyVal < pNode->val)
{
return _SearchNode(pNode->pLeft, keyVal);
}
else
{
return _SearchNode(pNode->pRight, keyVal);
}

}

RBNode* RBTree::_MinimumNode(int kevVal)
{
RBNode* pNode = _SearchNode(kevVal);
return _MinimumNode(pNode);
}

RBNode* RBTree::_MaximumNode(int kevVal)
{
RBNode* pNode = _SearchNode(kevVal);
return _MaximumNode(pNode);

}

RBNode* RBTree::_MinimumNode(RBNode* pNode)
{
if(pNode == m_Nil)
{
return m_Nil;
}

while(pNode->pLeft != m_Nil)
{
pNode = pNode->pLeft;
}

return pNode;
}

RBNode* RBTree::_MaximumNode(RBNode* pNode)
{
if(pNode == m_Nil)
{
return m_Nil;
}

while(pNode->pRight != m_Nil)
{
pNode = pNode->pRight;
}

return pNode;
}

RBNode* RBTree::_SuccessorNode(int keyVal)
{
RBNode* pNode = _SearchNode(keyVal);
return _SuccessorNode(pNode);

}

RBNode* RBTree::_SuccessorNode(RBNode* pNode)
{

if(pNode->pRight != m_Nil)
{
return _MinimumNode(pNode->pRight);
}

RBNode* pParNode = pNode->pParent;
///> 沿着父节点扶摇直上, 如果转向左边,
///> 则说明那个节点是后继. 不多解释, 请在网上看例图
while(pParNode != m_Nil && pNode == pParNode->pRight)
{
pNode = pParNode;
pParNode = pParNode->pParent;
}

return pParNode;
}

bool RBTree::Insert(int keyVal)
{
RBNode* pInsertPoint = m_root;
RBNode* pIndex = m_root;

if(m_root != NULL)
{
///> 循环结束后, pIndex降为空,
///> pInsertPoint则为要插入节点的父节点
while(pIndex != m_Nil)
{
pInsertPoint = pIndex;
if(keyVal < pIndex->val)
{
pIndex = pIndex->pLeft;
}
else if(keyVal > pIndex->val)
{
pIndex = pIndex->pRight;
}
else
{
return false;
}
}

///> 已经找到插入节点的位置, 按值大小来插入
if(keyVal < pInsertPoint->val)
{
pInsertPoint->pLeft = new RBNode(
m_Nil, m_Nil, pInsertPoint, keyVal);
///> 以上都是常规的二叉树代码.
///> 在红黑树中, 为了保持红黑性质, 则要进行整理
_InsertFixedUp(pInsertPoint->pLeft);
}
else
{
pInsertPoint->pRight = new RBNode(
m_Nil, m_Nil, pInsertPoint, keyVal);
///> 不解释
_InsertFixedUp(pInsertPoint->pRight);
}

m_size++;

}
///> 如果root节点为空, 则新建一个节点给root
else
{
///> 如果只有一个颜色为black的root节点, 则不需要整理
m_root = new RBNode(m_Nil, m_Nil, m_Nil, keyVal, black);
m_size++;
}
}

///> 插入一个红结点会破坏性质2(根结点为空的情况下)
///> 或者性质4(根结点不为空的情况下)
void RBTree::_InsertFixedUp(RBNode* pNode)
{
///> 如果满足父节点为红色. 则继续循环直到满足5条性质
while(pNode->pParent->color == red)
{
RBNode* pNodeParent = pNode->pParent;
RBNode* pNodePaBro;

///> 得到叔父节点, 赋值给pNodePaBro.
if(pNodeParent->pParent->pLeft == pNodeParent)
{
pNodePaBro = pNodeParent->pParent->pRight;
}
else
{
pNodePaBro = pNodeParent->pParent->pLeft;
}

///> 父节点和叔父节点都是红色,(父节点为红在while循环里判断了)
///> 全部赋值为黑. 并且祖父节点赋值为红.
///> 这样符合性质4, 性质5.
if(pNodePaBro->color == red)
{
pNodeParent->color          = black;
pNodePaBro->color           = black;
pNodeParent->pParent->color = red;
///> 将pNode节点赋值为它的祖父节点
pNode = pNode->pParent->pParent;
pNode = pNodeParent->pParent;
}
///> 当前父节点是祖父节点的左子节点,
///> 节点的父节点是红色,叔叔节点是黑色,
///> 当前节点是其父节点的左子节点
///> 解法:父节点变为黑色,祖父节点变为红色,以祖父节点为支点右旋.
else if(pNodeParent->pParent->pLeft == pNodeParent &&
pNodeParent->pLeft          == pNode         )
{
pNodeParent->color = black;
pNodeParent->pParent->color = red;
_RightRotate(pNode->pParent->pParent);
break;
}
///> 当前父节点是祖父节点的左子节点,
///> 节点的父节点是红色,叔叔节点是黑色,
///> 当前节点是其父节点的左子节点
///> 解法:当前节点的父节点做为新的当前节点,以新当前节点为支点左旋.
else if(pNodeParent->pParent->pLeft == pNodeParent &&
pNodeParent->pRight         == pNode         )
{
pNode = pNode->pParent;
_LeftRotate(pNode);
}
///> 当前父节点是祖父节点的右子节点,
///> 节点的父节点是红色,叔叔节点是黑色,
///> 当前节点是其父节点的左子节点
///> 解法:当前节点的父节点做为新的当前节点,以新当前节点为支点右旋.
else if(pNodeParent->pParent->pRight == pNodeParent &&
pNodeParent->pLeft           == pNode         )
{
pNode = pNode->pParent;
_RightRotate(pNode);
}
///> 当前父节点是祖父节点的右子节点,
///> 节点的父节点是红色,叔叔节点是黑色,
///> 当前节点是其父节点的右子节点
///> 解法:当前节点的父节点做为新的当前节点,以祖父节点为支点左旋.
else
{
pNodeParent->color = black;
pNodeParent->pParent->color = red;
_LeftRotate(pNode->pParent->pParent);
break;
}
}///> while(pNode->pParent->color == red)

///> 性质2: 根节点必须为黑色
m_root->color = black;
}

///> _InsertFixedUp2和上面的_InsertFixedUp运算结果一样的, 虽然代码不一样
void RBTree::_InsertFixedUp2(RBNode* pNode)
{
RBNode* pUncleNode = m_Nil;
///> 如果满足父节点为红色. 则继续循环直到满足5条性质
while(pNode->pParent->color == red)
{

if(pNode->pParent == pNode->pParent->pParent->pLeft)
{
pUncleNode = pNode->pParent->pParent->pRight;

///> 父节点和叔父节点都是红色,(父节点为红在while循环里判断了)

d001
///> 全部赋值为黑. 并且祖父节点赋值为红.
///> 这样符合性质4, 性质5.
if(pUncleNode->color == red)
{
pUncleNode->color = black;
pNode->pParent->pParent->color = red;
///> 将pNode节点赋值为它的祖父节点来上移节点以
///> 从下到上整理使树满足红黑性质
pNode = pNode->pParent->pParent;
}
///> 如果叔父节点为黑色
else
{
///> 如果node是右孩子, 且父节点为红色
///> 叔父节点为黑色, 那么进行左旋(左旋是什么我就不多说了)
if(pNode == pNode->pParent->pRight)
{
pNode = pNode->pParent;
_LeftRotate(pNode);
}
///> 把原本是红色的父节点变为黑色, 祖父节点变为红色
///> 然后以祖父节点右旋
else
{
pNode->pParent->color = black;
pNode->pParent->pParent->color = red;
_RightRotate(pNode->pParent->pParent);
}
}
}
else if(pNode->pParent == pNode->pParent->pParent->pRight)
{
pUncleNode = pNode->pParent->pParent->pLeft;

///> 父节点和叔父节点都是红色,(父节点为红在while循环里判断了)
///> 全部赋值为黑. 并且祖父节点赋值为红.
///> 这样符合性质4, 性质5.
if(pUncleNode->color == red)
{
pNode->pParent->color = black;
pUncleNode->color = black;
pUncleNode->pParent->color = red;
///> 将pNode节点赋值为它的祖父节点来上移节点以
///> 从下到上整理使树满足红黑性质
pNode = pNode->pParent->pParent;
}
else if(pUncleNode->color == black)
{
if(pNode == pNode->pParent->pLeft)
{
pNode = pNode->pParent;
_RightRotate(pNode);
}
else
{
///> 不解释, 除了旋转什么都没变 (●′ω`●)
pNode->pParent->color = black;
pNode->pParent->pParent->color = red;
_LeftRotate(pNode->pParent->pParent);
}
}
}
}
///> 红黑树第二条性质, 不解释~亲
m_root->color = black;
}

bool RBTree::DeleteNode(int keyVal)
{
///> 前大部分是普通的二叉树删除, 删除后,
///> 会进行红黑整理来维持红黑树性质
RBNode* pSubstitute = m_Nil;
RBNode* pNodeDel = m_Nil;
RBNode* pNode = _SearchNode(keyVal);

if(pNode == m_Nil)
{
return false;
}

///> 如果要删除的节点没有2个孩子
if(pNode->pLeft == m_Nil || pNode->pRight == m_Nil)
{
pNodeDel = pNode;
}
else
{
///> 如果要删除的节点有2个孩子
///> 那么得到node的后继, 把要后继的val
///> 赋给要被删节点的val, 然后把node删掉,
///> node的孩子则成为node父亲的孩子
pNodeDel = _SuccessorNode(pNode);
}

///> 哪一端的孩子有效, 则让那孩子代替被删除的节点
if(pNodeDel->pLeft != m_Nil)
{
pSubstitute = pNodeDel->pLeft;
}
else
{
pSubstitute = pNodeDel->pRight;
}

///> 将pSubstitute的parent指针指向将被删除的节点的parent指针
pSubstitute->pParent = pNodeDel->pParent;

///> 如果为空, 那么删除后肯定就只有一颗光秃秃的树根,
///> 那么就直接让root为node
if(pNodeDel->pParent == m_Nil)
{
delete m_root;
m_root = pSubstitute;
}
///> 用左孩子代替被删节点
else if(pNodeDel == pNodeDel->pParent->pLeft)
{
pNodeDel->pParent->pLeft = pSubstitute;
}
///> 用右孩子代替被删节点
else
{
pNodeDel->pParent->pRight = pSubstitute;
}

///> 如果pNodeDel不等于pNode, 则说明要被删除的节点有两个孩子
///> 把要后继的val赋给要被删节点的val(前面注释中有说过)
if(pNodeDel != pNode)
{
pNode->val = pNodeDel->val;
}

///> 如果被删节点为黑色, 则破坏了性质5, 要FixUp
if(pNodeDel->color == black)
{
_DelFixedUp(pNode);
}

delete pNodeDel;
pNodeDel = NULL;

m_size--;
return true;
}

void RBTree::_DelFixedUp(RBNode* pNode)
{
RBNode* pBroNode;

///> 如果pNode不为root, 并且为黑色, 则破坏了性质5
while(pNode != m_root && pNode->color == black)
{
///> 如果位于左边,
///> 兄弟节点则为它的父节点的右孩子
if(pNode->pParent->pLeft == pNode)
{
pBroNode = pNode->pParent->pRight;

///> 如果兄弟节点为红色,
///> 则把兄弟节点改为黑色,
///> 父节点改为红色, 来维持性质5
if(pBroNode->color == red)
{
pBroNode->color = black;
pNode->pParent->color = red;
_LeftRotate(pNode->pParent);
}
///> 如果兄弟节点为黑色···↓
else
{
///>··且兄弟节点的左右孩子都为黑色
///>··则要把兄弟节点改为红色来维持性质4,5
if(pBroNode->pLeft->color == black &&
pBroNode->pRight->color == black )
{
pBroNode->color = red;
///> node沿树上移. 下次循环时整理上面的节点
pNode = pNode->pParent;
}
///>··否则如果只有兄弟的右孩子为黑色,
///>··则要把兄弟节点改为红色,
///>··则还要把左孩子改为黑色, 来维持性质4,5
else if(pBroNode->pRight->color == black)
{
pBroNode->color = red;
pBroNode->pLeft->color = black;
_RightRotate(pBroNode);
}
///>··兄弟节点是黑色, 右孩子为红色,
///>··左孩子有可能是红也可能是黑,
///>··则把兄弟节点的颜色改为父节点的颜色
///>··父节点则改为黑, 这样就平衡了而不违反性质4
else if(pBroNode->pRight->color == red)
{
pBroNode->color = pBroNode->pParent->color;
pBroNode->pParent->color = black;
pBroNode->pRight->color = black;
_LeftRotate(pBroNode->pParent);
pNode = m_root;

}
}
}
///> 否则如果位于右边,
///> 兄弟节点则为它的父节点的左孩子
///> 跟上面的相反, 就不多做注释了
else if(pNode->pParent->pRight == pNode)
{
pBroNode = pNode->pParent->pLeft;
if(pBroNode->color == red)
{
pBroNode->color = black;
pNode->pParent->color = red;
_RightRotate(pNode->pParent);
}
else
{
if(pBroNode->pLeft->color == black &&
pBroNode->pRight->color == black )
{
pBroNode->color = red;
pNode = pNode->pParent;
}
else if(pBroNode->pLeft->color == black)
{
pBroNode->color = red;
pBroNode->pRight->color = black;
_LeftRotate(pBroNode);
}
else if(pBroNode->pLeft->color == red)
{
pBroNode->color = pBroNode->pParent->color;
pBroNode->pParent->color = black;
pBroNode->pLeft->color = black;
_RightRotate(pBroNode->pParent);
pNode = m_root;
}
}
}

m_Nil->pParent = m_root;
}
pNode->color = black;
}

void RBTree::DisplayTree()
{
_DisplayTree(m_root);
}

///> 中序遍历, 递增输出
void RBTree::_DisplayTree(RBNode* pNode)
{
if(pNode == m_Nil)
{
return;
}

_DisplayTree(pNode->pLeft);

std::cout<<"node val: "<<pNode->val;
if(!pNode->color)
{
std::cout<<"\tcolor: black"<<std::endl;
}
else
{
std::cout<<"\tcolor: red"<<std::endl;
}

if(pNode->pLeft != m_Nil)
{
std::cout<<"\tleft node val: "<<pNode->pLeft->val;
}
else
{
std::cout<<"\tleft node is Nil";
}

if(!pNode->pLeft->color)
{
std::cout<<"\tcolor: black"<<std::endl;
}
else
{
std::cout<<"\tcolor: red"<<std::endl;
}

if(pNode->pRight != m_Nil)
{
std::cout<<"\tRight node val: "<<pNode->pLeft->val;
}
else
{
std::cout<<"\tRight node is Nil";
}
if(!pNode->pRight->color)
{
std::cout<<"\tcolor: black"<<std::endl;
}
else
{
std::cout<<"\tcolor: red"<<std::endl;
}

if(pNode->pParent != m_Nil)
{
std::cout<<"\tparent node val: "<<pNode->pLeft->val;
}
else
{
std::cout<<"\tparent node is Nil";
}
if(!pNode->pParent->color)
{
std::cout<<"\tcolor: black"<<std::endl;
}
else
{
std::cout<<"\tcolor: red"<<std::endl;
}

std::cout<<std::endl<<std::endl;

_DisplayTree(pNode->pRight);
}

int RBTree::GetSize()
{
return m_size;
}

int main()
{
RBTree* rbTree = new RBTree;

srand(time(0));
for(int i = 0; i < 100; ++i)
{
rbTree->Insert(rand()% 1000);
}

rbTree->DisplayTree();

std::cout<<rbTree->GetSize();
getchar();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C++ C 学习 排序 算法
相关文章推荐