/*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.
,[' ="' :?}`':` ~&^ `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循环里判断了)
///> 全部赋值为黑. 并且祖父节点赋值为红.
///> 这样符合性质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++源码, 有详细注释
最新推荐文章于 2022-02-25 18:19:43 发布