red and black trees(红黑二叉树)

来源:互联网 发布:淘宝助手与千牛 编辑:程序博客网 时间:2024/06/06 16:43

 一棵高度为 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>
usingnamespace 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) ;
}
elseif (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 ;
}
elseif (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
原创粉丝点击