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()
{
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>
usingnamespace 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) ;
}
elseif (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 ;
}
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->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
}
0 0
- red and black trees(红黑二叉树)
- POJ 1979 Red and Black(红与黑)
- POJ 1979 Red and Black(红与黑)
- “Red and Black(红黑瓷砖),ZOJ2165”的一种解法
- 暑假集训第三周周六赛 搜索 B - Red and Black红黑瓷片
- HDU 1312 Red and Black 红与黑 搜索 dfs bfs
- 算法导论C语言实现: 红黑(red-black tree)
- 红黑二叉树
- 红黑树(RED-BLACK TREES)基本概念
- RED-BLACK TREES
- Red-Black Trees
- Red-Black Trees
- Red-Black Trees 红黑树
- Red and Black(bfs)
- POJ1979(Red and Black)
- Red and Black(搜索)
- Red and Black(DFS)
- Red and Black(DFS)
- Algorithm Gossip: 蒙地卡罗法求PI
- Algorithm Gossip: 筛选求质数
- STL在ACM竞赛中的使用
- Best time to Buy and Sell Stock III
- Algorithm Gossip: 背包问题(Knapsack Problem)
- red and black trees(红黑二叉树)
- 技术总监(CTO)
- Flash Media Live Encoder MP3编码采样分析
- Mac OS X 10.6下安装MySQL 5.1.45
- 关于scrollView嵌套listView或者GridView
- Mac下MySql卸载方法
- PB数据窗口技巧
- 60个数据窗口技巧
- 也说说几种让程序员快速提高能力的方法