red and black trees(红黑二叉树)

 一棵高度为 h 的二叉查找树可以实现任何一种基本的动态集合操作, 如 SEARCH, PREDECESOR, SUCCESSOR, MINIMUM, MAXIMUM, INSERT, DELETE 等, 其时间都是 O(h). 这样, 当树的高度较低时, 这些操作就会执行的较快; 但是, 当树的高度较高时, 这些操作的性能可能不比用链表好红黑树(red-black tree)许多"平衡的"查找树中的一种, 它能保证在最坏情况下, 基本的动态集合操作的时间为 O(lg n). 

  红黑树是一种二叉查找树, 但在每个基点上增加一个存储位表示结点的颜色, 可以说是 RED 或 BLACK. 通过对任何一条从跟到叶子的路径上各个结点着色方式的限制, 红黑树确保没有一条路径会比其他路径长出两倍, 因而是接近平衡的.

 

红黑树的性质:
1) 每个结点或是 红的, 或是 黑的
2)  根结点是黑的
3) 每个 叶结点(NIL)是黑的. 
4) 如果一个 结点是红的, 则它的 两个儿子是黑的. 

5) 对每个结点, 从该结点到子孙结点的所有路径上包含相同数目的黑结点.


头文件:
复制代码
//  RBTree.h
//

#ifndef RBTree_H
#define  RBTree_H

#include 
< cstddef >

class  RBTree
{
public :
enum  Color{RED, BLACK} ;
struct  Node
{
Color c ;
Node 
* p,  * l,  * r ;
int  key ;

Node()
{
=  RED ;
=  l  =  r  =  NULL ;
key 
= 0  ;
}
} ;
public :
RBTree() ;
virtual ~ RBTree() ;
private :
RBTree(
const  RBTree  & other) ;
RBTree 
& operator = ( const  RBTree  & other) ;

public :
//  Interface
void  Insert( int  key) ;
void  Del( int  key) ;
void  Preorder() ;
void  Inorder() ;
Node 
* Search( int  key) ;
public :
//  logic
void  lr(Node  * p) ;
void  rr(Node  * p) ;
Node 
* successor(Node  * p) ;
Node 
* search(Node  * p,  int  key) ;
void  insert(Node  * root, Node  * p) ;
void  insert_fixup(Node  * p) ;
void  del(Node  * root, Node  * p) ;
void  del_fixup(Node  * p) ;

void  preorder(Node  * p) ;
void  inorder(Node  * p) ;

private :
//  data
Node  * root ;
Node 
* guard ;
} ;

template
< class  T >
inline 
void  EXCHANGE(T  & a, T  & b)
{
T c(a) ;
=  b ;
=  c ;
}

#endif //  RBTree_H
复制代码

源文件:
复制代码
//  RBTree.cpp
//

#include 
" RBTree.h "
#include 
< iostream >
#include 
< cassert >
#include 
< limits >
using namespace  std ;

RBTree::RBTree()
{
guard 
= new  Node ;
guard
-> =  guard -> =  guard -> =  guard ;
guard
-> =  BLACK ;
guard
-> key  =  numeric_limits < int > ::min() ;

root 
=  guard ;
}
RBTree::
~ RBTree()
{
delete guard ;
guard 
=  NULL ;
}

//  Interface
void  RBTree::Insert( int  key)
{
Node 
* = new  Node ;
p
-> =  p -> =  p -> =  guard ;
p
-> =  RED ;
p
-> key  =  key ;

insert(root, p) ;
}
void  RBTree::Del( int  key)
{
del(root, Search(key)) ;
}

void  RBTree::Preorder()
{
preorder(root) ;
}
void  RBTree::Inorder()
{
inorder(root) ;
}
RBTree::Node 
* RBTree::Search( int  key)
{
return  search(root, key) ;
}


//  logic
void  RBTree::lr(Node  * p)
{
//  We can't rotate a null pointer or a guard
if  (NULL  ==  p  ||  guard  ==  p)
{
return  ;
}
// if

//  'p' must has right child
assert(p -> r) ;

//  'rChild' will become new rotating root
Node  * parent  =  p -> p ;
Node 
* rChild  =  p -> r ;

//  Connect 'rChild' with 'parent'
if  (guard  ==  parent)
{
root 
=  p -> r ;
}
else
{
(p 
==  parent -> ?  parent -> l : parent -> r)  =  rChild ;
}
// if
rChild -> =  parent ;
//  'p' should take 'rChild' 's left child as its right child
p -> =  rChild -> l ;
rChild
-> l -> =  p ;
//  Put 'p' as 'rChild' 's left child
p -> =  rChild ;
rChild
-> =  p ;
}
void  RBTree::rr(Node  * p)
{
//  We can't rotate a null pointer or a guard
if  (NULL  ==  p  ||  guard  ==  p)
{
return  ;
}
// if

//  'p' must has right child
assert(p -> r) ;

//  I abstrct the root rotating procedure
//  Of course, this may be confuse at first sight
//  I'm sure after reading and thinking over, you'd must know it worth -- reconstitution
Node  *& r_c  =  p -> l ;  //  'r_c' is the storage of rotate's child
Node  *& r_c_c  =  p -> l -> r ;  //  'r_c_c' is the storage of rotate's child's child
Node  * parent  =  p -> p ;  //  'parent' is the address of 'p' 's parent
Node  * child  =  r_c ;  //  'child' is the address of the rotate

//  Connect 'parent' and new rotating root
child -> =  parent ;
if  (guard  ==  parent)
{
//  If 'p' is root, we must set 'root' point to new rotating root
root  =  child ;
}
else
{
//  If 'p' is not root,
//  we should set the storage which to store address of 'p' point to new rotating root
(p  ==  parent -> ?  parent -> l : parent -> r)  =  child ;
}
// if
//  Set 'p' 's child point to 'child' 's child which need to connect with other parent
r_c  =  r_c_c ;
guard 
==  r_c_c  ?  guard : r_c_c -> =  p ;
//  Rotate 'p' and 'child'
r_c_c  =  p ;
p
-> =  child ;
}

RBTree::Node 
* RBTree::successor(Node  * p)
{
assert(NULL 
!=  p) ;
//  guard has no successor
if  (guard  ==  p)
{
return  guard ;
}

if  (guard  ==  p -> r)
{
Node 
* parent  =  p -> p ;
while  (guard  !=  parent  &&  p  ==  parent -> r)
{
=  parent ;
parent 
=  parent -> p ;
}
// while

=  parent ;
}
else //  guard != p->r
{
=  p -> r ;
while  (guard  !=  p -> l)
{
=  p -> l ;
}
// while
} // if

return  p ;
}

RBTree::Node 
* RBTree::search(Node  * p,  int  key)
{
while  (guard  !=  p  &&  key  !=  p -> key)
{
=  key  >  p -> key  ?  p -> r : p -> l ;
}
// while

return  p ;
}

void  RBTree::insert(Node  * root_, Node  * p)
{
Node 
* parent  =  root_ -> p ;
Node 
* cur  =  root_ ;
while  (guard  !=  cur)
{
parent 
=  cur ;
cur 
=  p -> key  >  cur -> key  ?  cur -> r : cur -> l ;
guard
-> =  parent ;
}
// while

p
-> =  parent ;
if  (guard  ==  parent)
{
p
-> =  BLACK ;
root 
=  p ;
guard
-> =  guard -> =  guard -> =  root ;
}
else
{
(p
-> key  <  parent -> key  ?  parent -> l : parent -> r)  =  p ;
}
// if

if  (RED  ==  parent -> c)
{
insert_fixup(p) ;
}
// if
}

void  RBTree::insert_fixup(Node  * p)
{
//  'p' is always the red child who has a red parent
while  (RED  ==  p -> &&  RED  ==  p -> p -> c)
{
//  'ancestor' must be black
Node  * ancestor  =  p -> p -> p ;
Node 
* parent  =  p -> p ;
if  (parent  ==  ancestor -> l)
{
Node 
* uncle  =  ancestor -> r ;

if  (RED  ==  uncle -> c)
{
//  If 'p' 's uncle is red
//  we transport the color of black parent down to its two children
//  and move 'p' to its ancestor for the next collision if 'ancestor' 's parent is red either
ancestor -> =  RED ;
ancestor
-> l -> =  ancestor -> r -> =  BLACK ;
=  ancestor ;
}
else
{
//  If 'p' 's uncle is black
//  we'd use 'ancestor' as root to right rotate,
//  'parent' will become new root of the sub tree after rotating
//  and swap the color of 'p' 's parent with its parent('ancestor')
//  but we must consider if 'p' is right of its parent
//  in this situation, we should right rotate 'p' 's parent before right rotating
//  lastly, we know that 'p' is always the red child who has a red parent
//  so we reset 'p' after each rotating
if  (parent -> ==  p)
{
//  'p' is right child of its parent
lr(parent) ;
//  Reset 'p' and 'parent' to new position
=  parent ;
parent 
=  parent -> p ;
}
// if
EXCHANGE(ancestor -> c, parent -> c) ;
rr(ancestor) ;
//  Reset 'p' to the red child of a red parent
=  parent ;
//  Here exit loop
} // if
}
else
{
//  There are three cases needs fixing
//  a) 'parent' and 'uncle' are red, while 'ancestor' is black
//  b) 'parent' are red, while 'uncle' and 'ancestor' is black, 'p' is left child of 'parent'
//  c) 'parent' are red, while 'uncle' and 'ancestor' is black, 'p' is right child of 'parent'
Node  * uncle  =  ancestor -> l ;

//  'ancestor' must be black if exists
if  (RED  ==  uncle -> c)
{
//  If a black 'ancestor' has two red children,
//  we just exchange 'ancestor' 's color with it's two children
//  and reset 'p' to 'ancestor' to asking upper level for solution
ancestor -> =  RED ;
parent
-> =  uncle -> =  BLACK ;
=  ancestor ;
}
else //  RED == uncle->c
{
//  If a black 'ancestor' has a red left child and a black right child
//  we should exchange 'ancestor' 's color with 'parent'
//  and then do right rotating to rebalance the tree
//  after those two operations, we solve the collision without impacting black high
//  If 'p' is left child of its parent, we need do right rotating to
//  switch into another structure without any other effect
//  the new structure is a prepare for left rotating of 'ancestor'
if  (parent -> ==  p)
{
rr(parent) ;
=  parent ;
parent 
=  parent -> p ;
}
// if

EXCHANGE(ancestor
-> c, parent -> c) ;
lr(ancestor) ;
}
// if RED == uncle->c
} // if parent == ancestor->l
} // while

root
-> =  BLACK ;
}
void  RBTree::del(Node  * root, Node  * p)
{
//  Can't delete guard node
if  (guard  ==  p)
{
return  ;
}
// if

//  'toDel' is the real node which will delete at last
Node  * toDel  =  p ;
//  'toFix' is the position where 'toDel' originally site
Node  * toFix  =  guard  ==  toDel -> ?  toDel -> r : toDel -> l ;

//  If 'p' has two children, we should delete its successor
if  (guard  !=  p -> &&  guard  !=  p -> r)
{
toDel 
=  successor(p) ;
}
// if

//  Disconnect 'toDel' and connect 'parent' and 'child'
Node  * child  =  guard  ==  toDel -> ?  toDel -> r : toDel -> l ;
Node 
* parent  =  toDel -> p ;
child
-> =  parent ;
if  (guard  ==  parent)
{
root 
=  child ;
}
else
{
(parent
-> ==  toDel  ?  parent -> l : parent -> r)  =  child ;
}
// if

if  (p  !=  toDel)
{
p
-> key  =  toDel -> key ;
}
// if

if  (BLACK  ==  toDel -> c)
{
cout 
<< " fixing " << endl ;
del_fixup(toFix) ;
}
// if

delete toDel ;
//  toDel = NULL ;  //  Meaningless
}
void  RBTree::del_fixup(Node  * p)
{
//
Node  * parent  =  p -> p ;
Node 
* brother  =  guard ;
Node 
* nephew  =  guard ;  //  'brother's' left child
Node  * niece  =  guard ;  //  'brother's' right child

while  (root  !=  p  &&  BLACK  ==  p -> c)
{
//  Every time we rotating, we just need reset 'p' to build relationship
//  because all relationship depend on 'p'
if  (parent -> ==  p)
{
//  Every condition branch is a point where to enter.
//  only b) and d) is Exit Model
//  it means when enter case a) or c), we must try to transform into case b) or d)

parent 
=  p -> p ;
brother 
=  parent -> r ;
nephew 
=  brother -> l ;
niece 
=  brother -> r ;

//  We divide all cases into four
//  a) 'brother' is red, it means parent must black and both 'nephew' and 'niece' are black
//  b) 'brother' is black, while both 'nephew' and 'niece' are black
//  c) 'brother' is black, 'nephew' is black but 'niece' is red
//  d) 'brother' is black, 'niece' is red, no mater 'nephew' 's color
if  (RED  ==  brother -> c)
{
//  BLACK == 'parent->c'
//  BLACK == 'nephew->c'
//  BLACK == 'niece->c'
//  If 'brother' is red, we try to turn it into black
//  we can't change its childrens' color
EXCHANGE(parent -> c, brother -> c) ;
lr(parent) ;
}
else if  (BLACK  ==  niece -> &&  BLACK  ==  nephew -> c)
{
//  BLACK == 'brother->c'
//  We can't solve problem in this level,
//  so we abstract one level black from 'p' and 'brother'
//  now, 'p' has only one black level and 'brother' turn into red
//  and then, move 'p' to it's parent to expect solution
brother -> =  RED ;
=  parent ;
}
else if  (BLACK  ==  niece -> c)
{
//  BLACK == 'brother->c'
//  RED == 'newphew->c'
//  We need it's niece be red
EXCHANGE(brother -> c, nephew -> c) ;
rr(brother) ;
}
else
{
//  BLACK == 'brother->c'
//  RED == 'niece->c'
//  This is we wanted model,
//  and this is the exit of loop
lr(parent) ;
EXCHANGE(parent
-> c, brother -> c) ;
parent
-> =  niece -> =  BLACK ;

//  The loop will break out
=  brother ;
}
//  RED == brother->c
}
else //  p->l != p
{
//  I process case c) and d) together, bacause case c) should transform to case d)
//  so, now we have enter point

parent 
=  p -> p ;
brother 
=  parent -> l ;
nephew 
=  brother -> l ;
niece 
=  brother -> r ;

//  There are four cases
//  a) 'brother' is RED, we need turn it into BLACK
//  b) 'brother' and its two children are all BLACK, this case we can abstract
//  BLACK from 'p' and 'brother',
//  turning 'p' to 'parent' ask upper level for solution if 'parent' is BLACK either
//  otherwise, draw 'parent' to BLACK to solve the problem
//  c) 'brother' is BLACK, 'nephew' is BLACK but 'niece' is RED, we should use
//  Equivalent Conversion to change into case d)
//  d) 'brother' is BLACK, 'nephew' is RED. This is Exit Model
if  (RED  ==  brother -> c)
{
//  This is a non-Exit Model, we try to switch it to Exit Model
//  Case a)
EXCHANGE(parent -> c, brother -> c) ;
rr(parent) ;
}
else //  RED != brother->c
{
//  This is Exit Model
//  Now, 'brother' 's color is BLACK
if  (BLACK  ==  nephew -> &&  BLACK  ==  niece -> c)
{
//  Case b)
//  In this case, may cause loop
//  We decrease a layer of BLACK from 'brother' and 'p'
//  Now, 'brother' turn into RED while 'p' has only one level BLACK
brother -> =  RED ;
//  We set 'p' to 'parent'
//  to put the extra BLACK to parent in order to keep balance
=  parent ;
}
else
{
if  (BLACK  ==  nephew -> c)
{
//  Case c)
//  We can turn this case into case d) for solution
EXCHANGE(brother -> c, niece -> c) ;
lr(brother) ;
//  Reset 'brother' and 'nephew' and 'niece'
brother  =  parent -> l ;
nephew 
=  brother -> l ;
niece 
=  brother -> r ;
}
// if BLACK == nephew->c

//  Case d)
//  After this rotating, loop will exit!
rr(parent) ;
//  Reset all relationship
=  parent ;
parent 
=  brother ;
brother 
=  parent -> l ;
nephew 
=  brother -> l ;
niece 
=  brother -> r ;
parent
-> =  p -> c ;
brother
-> =  p -> =  BLACK ;

//  Here exit loop
=  parent ;
}
// if BLACK == nephew->c && BLACK == niece->c
} // if RED == brother->c
} // if p->l == p
} // while

p
-> =  BLACK ;
}

void  RBTree::preorder(Node  * p)
{
if  (guard  !=  p)
{
preorder(p
-> l) ;
cout 
<< p -> key  << "  :  "  ;
cout 
<< (RED  ==  p -> ? " Red "  :  " Black " ) ;
cout 
<< endl ;
preorder(p
-> r) ;
}
// if
}
void  RBTree::inorder(Node  * p)
{
if  (guard  !=  p)
{
cout 
<< p -> key  << "  :  "  ;
cout 
<< (RED  ==  p -> ? " Red "  :  " Black " ) ;
cout 
<< endl ;
inorder(p
-> l) ;
inorder(p
-> r) ;
}
// if
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值