红黑树 (Red-Black Tree)


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

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

 

红黑树的性质:
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()
{
c
= RED ;
p
= 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) ;
a
= b ;
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
-> p = guard -> l = guard -> r = guard ;
guard
-> c = BLACK ;
guard
-> key = numeric_limits < int > ::min() ;

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

// Interface
void RBTree::Insert( int key)
{
Node
* p = new Node ;
p
-> p = p -> l = p -> r = guard ;
p
-> c = 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 -> l ? parent -> l : parent -> r) = rChild ;
}
// if
rChild -> p = parent ;
// 'p' should take 'rChild' 's left child as its right child
p -> r = rChild -> l ;
rChild
-> l -> p = p ;
// Put 'p' as 'rChild' 's left child
p -> p = rChild ;
rChild
-> l = 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 -> p = 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 -> l ? 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 = p ;
// Rotate 'p' and 'child'
r_c_c = p ;
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)
{
p
= parent ;
parent
= parent -> p ;
}
// while

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

return p ;
}

RBTree::Node
* RBTree::search(Node * p, int key)
{
while (guard != p && key != p -> key)
{
p
= 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
-> p = parent ;
}
// while

p
-> p = parent ;
if (guard == parent)
{
p
-> c = BLACK ;
root
= p ;
guard
-> p = guard -> l = guard -> r = 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 -> c && 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 -> c = RED ;
ancestor
-> l -> c = ancestor -> r -> c = BLACK ;
p
= 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 -> r == p)
{
// 'p' is right child of its parent
lr(parent) ;
// Reset 'p' and 'parent' to new position
p = parent ;
parent
= parent -> p ;
}
// if
EXCHANGE(ancestor -> c, parent -> c) ;
rr(ancestor) ;
// Reset 'p' to the red child of a red parent
p = 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 -> c = RED ;
parent
-> c = uncle -> c = BLACK ;
p
= 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 -> l == p)
{
rr(parent) ;
p
= parent ;
parent
= parent -> p ;
}
// if

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

root
-> c = 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 -> l ? toDel -> r : toDel -> l ;

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

// Disconnect 'toDel' and connect 'parent' and 'child'
Node * child = guard == toDel -> l ? toDel -> r : toDel -> l ;
Node
* parent = toDel -> p ;
child
-> p = parent ;
if (guard == parent)
{
root
= child ;
}
else
{
(parent
-> l == 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 -> l == 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 -> c && 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 -> c = RED ;
p
= 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
-> c = niece -> c = BLACK ;

// The loop will break out
p = 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 -> c && 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 -> c = RED ;
// We set 'p' to 'parent'
// to put the extra BLACK to parent in order to keep balance
p = 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
p = parent ;
parent
= brother ;
brother
= parent -> l ;
nephew
= brother -> l ;
niece
= brother -> r ;
parent
-> c = p -> c ;
brother
-> c = p -> c = BLACK ;

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

p
-> c = BLACK ;
}

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

转载于:https://www.cnblogs.com/walfud/archive/2011/05/17/2048602.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值