一棵高度为 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()
{
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
}