红黑树的C++实现
关于红黑树,可以参考《算法导论》第三版第13章,在CSDN上也有很多文章讲述,在此不再具体讲述。主要说一下自己对红黑树的一些理解。
1.红黑树是平衡树的一种,红黑树不同于AVL树,它牺牲了严格的高度平衡的,只要求局部的达到平衡要求,从而降低了对旋转的要求,提高了性能。严格意义上,红黑树的高度至多为2lg(n+1)
2.在算法导论中,红黑树的实现有一个很重要的一点就是设置了哨兵nil,哨兵的颜色设置为黑色,并且将所有叶节点的左右孩子设置为nil,将根的父节点也设置为nil,这样设计的目的是为了方便插入删除,否则的话需要经常测试是否为根节点,叶子节点,而且对于这些节点的插入删除情况还要和其它节点区分开来。这一点在程序中可以仔细的体悟。
源代码下载地址:http://download.csdn.net/detail/u010772289/9416611
具体C++实现如下:
//RedBlackTree.h
/*
* 算法导论第13章:红黑树 C++实现
* 功能:查找find,插入insert,删除erase,最大值max,最小值min 销毁destroy
* 红黑树性质:
* 1.节点为红/黑
* 2.根节点为黑
* 3.叶节点(nil)均为黑
* 4.红节点的两个子节点必须为黑
* 5.每条简单路径黑节点数相同
*/
#include <initializer_list>
#ifndef __REDBLACKTREE_H__
#define __REDBLACKTREE_H__
class RedBlackTree{
private:
struct Node;
public:
typedef Node *Position, *RBTree;
enum Color{ RED = 0, BLACK };
public:
using ElemmentType = int;
RedBlackTree();
RedBlackTree(const std::initializer_list<ElemmentType>&); //列表初始化
~RedBlackTree();
Position max(RBTree T);
Position min(RBTree T);
Position max(){ return max(root); }
Position min(){ return min(root); }
Position find(ElemmentType X); //查找
void insert(ElemmentType X);
void erase(ElemmentType X);
void destroy(); //销毁
void PrintRBTree();
ElemmentType key(Position P){ return P->key; }
Color color(Position P){ return P->color; }
Color color(ElemmentType X){ Position P = find(X); return color(P); }
Position left(Position P){ return P->left; }
Position right(Position P){ return P->right; }
Position parent(Position P){ return P->parent; }
private:
RBTree root; //根节点
RBTree nil; //哨兵
void insert_fixup(Position z);
void left_rotate(RBTree T); // 左旋
void right_rotate(RBTree T); //右旋
void destroy(RBTree T);
void RB_TransPlant(RBTree x, RBTree y); //以子树y替换子树x
void RB_Delete_Fixup(Position x); //删除黑色节点后,重新调整红黑树
void PrintRBTree(RBTree T);
static const ElemmentType UnInfinity = -65535;
struct Node{
Node()=default;
Node(ElemmentType _key, Node* _left, Node* _right,Node* _parent, Color _clolor)
:key(_key),left(_left),right(_right),parent(_parent),color(_clolor){}
//~Node();
ElemmentType key=UnInfinity;
Node* left=nullptr; //左孩子
Node* right=nullptr; //右孩子
Node* parent=nullptr; //父节点
Color color = RED; //颜色,默认为红
};
};
#endif //RedBlackTree.h
#include <stdexcept>
#include <iostream>
#include "RedBlackTree.h"
using std::initializer_list;
RedBlackTree::RedBlackTree() :nil(new Node())
{
nil->color = BLACK;
root = nil;
}
RedBlackTree::RedBlackTree(const initializer_list<ElemmentType>& il) :nil(new Node())
{
nil->color = BLACK;
root = nil;
for (initializer_list<ElemmentType>::const_iterator it = il.begin(); it != il.end(); ++it)
insert(*it);
}
RedBlackTree::~RedBlackTree()
{
destroy();
}
RedBlackTree::Position RedBlackTree::max(RBTree T)
{
Position p=T;
if (p!=nil)
while (p->right != nil)
p = p->right;
return p;
}
RedBlackTree::Position RedBlackTree::min(RBTree T)
{
Position p = T;
if (p != nil)
while (p->left != nil)
p = p->left;
return p;
}
RedBlackTree::Position RedBlackTree::find(ElemmentType X)
{
Position P = root;
while (P != nil){
if (P->key < X)
P = P->right;
else if (P->key>X)
P = P->left;
else
break;
}
return P;
}
void RedBlackTree::insert(ElemmentType X)
{
Position P = root;
Position lastP = nil;
while (P != nil ){
lastP = P;
if (P->key < X)
P = P->right;
else if (P->key>X)
P = P->left;
else
break;
}
if (P == nil){ // X不存在于红黑树中时
Position tmp;
tmp = new Node(); //新节点
tmp->key = X;
tmp->parent = lastP; //设置新节点父亲,根节点父亲设为nil
tmp->left = tmp->right = nil;
if (lastP == nil){ //设置根节点
tmp->color = BLACK; //根节点必须为黑色
root = tmp;
}
else if (X < lastP->key) //插入
lastP->left = tmp;
else
lastP->right = tmp;
if (lastP != nil && lastP->color == RED) //新插入节点父亲若为红色,则需要调整
insert_fixup(tmp);
}
}
/*
* insert_fixup:插入的新节点父亲为红时进行调整
* 时间:O(lgN),只有在情况1 while 循环才会重复执行
* 左子树三种情况:
* 1.z的叔节点是红色 解决:z上移
* 2.z的叔节点是黑色且z为右孩子 解决:转为情况3
* 3.z的叔节点是黑色且z为左孩子
* 右子树类似
*/
void RedBlackTree::insert_fixup(Position z)
{
while (z->parent->color == RED){ //红节点的父亲为黑色时停止(注意:哨兵nil的颜色为黑色)
if (z->parent == z->parent->parent->left){ //左子树
if (z->parent->parent->right->color == RED){ //情况1
z->parent->color = BLACK;
z->parent->parent->color = RED;
z->parent->parent->right->color = BLACK;
z = z->parent->parent; //z上移,设置新的z
}
else{
if (z == z->parent->right){ //情况2
z = z->parent;
left_rotate(z);
}
z->parent->color = BLACK;//情况3
z->parent->parent->color = RED;
right_rotate(z->parent->parent);
}
}
else{ //右子树
if (z->parent->parent->left->color == RED){ //情况1
z->parent->color = BLACK;
z->parent->parent->color = RED;
z->parent->parent->left->color = BLACK;
z = z->parent->parent; //上移
}
else {
if (z == z->parent->left){ //情况2
z = z->parent;
right_rotate(z);
}
z->parent->color = BLACK;
z->parent->parent->color = RED;
left_rotate(z->parent->parent);
}
}
}
root->color = BLACK;
}
void RedBlackTree::RB_TransPlant(RBTree x, RBTree y) //以子树y替换子树x
{
if (x->parent == nil) //若x为根节点
root = y;
else if (x == x->parent->left)
x->parent->left = y;
else
x->parent->right = y;
y->parent = x->parent; //y为nil时也设置了其父节点
}
void RedBlackTree::erase(ElemmentType X)
{
Position p = find(X);
Position x=nil; //待删除的节点的下一点
Color cl = p->color; //cl记录待删除节点的颜色
if (p == nil)
throw std::runtime_error("The elemment does not exit!");
if (p->left == nil){
x = p->right; //p为待删除点,x为其下一点
RB_TransPlant(p, p->right);
}
else if (p->right == nil){
x = p->left;
RB_TransPlant(p, p->left);
}
else {
Position y = min(p->right);
cl = y->color;
RB_TransPlant(y, y->right);
RB_TransPlant(p, y);
y->left = p->left;
y->right = p->right;
y->left->parent = y;
//if (y->right != nil)
y->right->parent = y;
}
//x->parent = p->parent; /// http://www.2cto.com/kf/201307/229160.html
delete p;
//PrintRBTree();
if (cl == BLACK) //若删除了黑色节点,调整红黑树
RB_Delete_Fixup(x);
}
/*
* RB_Delete_Fixup: 删除黑色节点后的调整工作
* 左子树,四种情况:
* 1.x的兄弟节点为红色 解决:转为情况2,3,4
* 2.x的兄弟节点w为黑色,w的两个子节点都是黑色的 解决:x,w各去掉一层黑色,将x.p添加一层黑色,x上移
* 3.x的兄弟节点w为黑色,w的右孩子是黑色的,左孩子是红色的 解决:转为情况4
* 4.x的兄弟节点w为黑色,w的右孩子红色的 解决:右旋,结束
* 右子树类似
*/
/*
无论哪种情况删除的都是结点z,而y代表了被“删除”的结点的位置,无论y是z本身还是z的后继结点,
y原来位置的结点都被删除或者移走了了,而x则代表了取代y位置结点的那个结点
(x结点可以是哨兵结点nil,这时nil就体现了它作为哨兵结点的作用,因为nil->p=y,指向了被“删除”结点的位置),
被删除的结点y为黑色,那么根结点到x结点的路径(x是nil结点时,也与性质5相吻合)中的黑色结点数目将会减少1
*/
void RedBlackTree::RB_Delete_Fixup(Position x)
{
Position w = nil;
while (x != root && x->color == BLACK){ //x为根节点或者为红色时循环停止
if (x == x->parent->left){ //左子树
w = x->parent->right; //
if (w->color == RED) { //情况1
x->parent->color = RED;
w->color = BLACK;
left_rotate(x->parent);
w = x->parent->right; //更新w
}
if (w->left->color == BLACK && w->right->color == BLACK){ //情况2
w->color = RED; //x,w去掉一层黑色(w变为红,x由两层黑色变为1层黑色)
x = x->parent; //x上移,进行while循环
}
else {
if (w->right->color == BLACK && w->left->color == RED){ //情况3
w->color = RED;
w->left->color = BLACK;
right_rotate(w);
w = x->parent->right;
}
w->color = x->parent->color; //情况4
x->parent->color = BLACK;
w->right->color = BLACK;
left_rotate(x->parent);
x = root; //退出while循环
}
}
else{ //右子树
w = x->parent->left;
if (w->color == RED){ //情况1
w->color = BLACK;
x->parent->color = RED;
right_rotate(x->parent);
w = x->parent->left;
}
if (w->left->color == BLACK && w->right->color == BLACK){ //情况2
w->color = BLACK;
x = x->parent;
}
else {
if (w->left->color == BLACK && w->right->color == RED){ //情况3
w->right->color = BLACK;
w->color = RED;
left_rotate(w);
w = x->parent->left;
}
w->color = x->parent->color; //情况4
x->parent->color = BLACK;
w->left->color = BLACK;
right_rotate(x->parent);
x = root;
}
}
}
x->color = BLACK; ///
}
void RedBlackTree::destroy(RBTree T)
{
if (T!=nil){
destroy(T->left);
delete T;
destroy(T->right);
}
}
void RedBlackTree::destroy() //销毁
{
destroy(root);
delete nil;
}
void RedBlackTree::PrintRBTree()
{
PrintRBTree(root);
}
void RedBlackTree::PrintRBTree(RBTree T)
{
if (T != nil){
PrintRBTree(T->left);
//std::cout << T->key << " : " << T->color << "\t";
std::cout << T->key << "\t";
PrintRBTree(T->right);
}
}
void RedBlackTree::left_rotate(RBTree y) // 左旋
{
Position x = y->right;
y->right = x->left;
x->parent = y->parent;
//if (y->right != nil) //原来y的右孩子未指向哨兵nil,则设置其父亲
y->right->parent = y;
if (y->parent == nil){
//x->parent = nil;
root = x;
}
else if (y == y->parent->left)
y->parent->left = x;
else
y->parent->right = x;
x->left = y;
y->parent = x;
}
void RedBlackTree::right_rotate(RBTree x) //右旋
{
Position y = x->left;
x->left = y->right; //设置x左孩子
//if (x->left!=nil) //x左孩子的父亲
x->left->parent = x;
y->parent = x->parent; //设置y
if (x->parent == nil) //若原来x为根节点,则设置y为新的根节点
root = y;
else if (x == x->parent->left)
x->parent->left = y;
else
x->parent->right = y;
y->right = x; //连接x,y
x->parent = y;
}
#include <iostream>
#include "RedBlackTree.h"
using std::cout;
using std::endl;
int main()
{
RedBlackTree T;
for (int i = 5; i < 10; ++i)
T.insert(i);
for (int i = 5; i < 10; ++i){
T.erase(i);
T.PrintRBTree();
std::cout << endl;
}
return 0;
}