#ifndef RBTREE_H_
#define RBTREE_H_
#include <iostream>
#include <string>
using namespace std;
#define BLACK 0
#define RED 1
struct Node
{
int key; //节点键值
string ID;
int color; //节点颜色
Node *left; //左叶节点
Node *right; //右叶节点
Node *parent; //父节点
};
class RBTree
{
private:
Node *root; //根节点
Node *nil; //哨兵,颜色为BLACK
int bHeight; //黑高
int nodeNum; //节点个数
void LeftRotate(Node *x); //左旋转
void RightRotate(Node *x); //右旋转
void InsertFixup(Node *p); //插入节点p时维护红黑树性质
void Transplant(Node *u, Node *v); //用另一棵子树替换一棵子树并成为其双亲的孩子结点
void DeleteFixup(Node *x); //删除结点时维护红黑树性质
public:
RBTree();
void Destory(Node *p); //销毁树
Node *Minimum(Node *x); //最小键值结点
Node *Maximum(Node *x); //最大键值结点
Node *Successor(Node *x); //后继
Node *Predecessor(Node *x); //前驱
Node *Search(Node *x,int k); //搜索树
void Insert(Node *z); //插入节点
void Delete(int k); //删除结点,该结点键值为k
void Out(Node *p);
void Display();
};
/*
功能:左旋转
条件:x的右孩子y不是nil
步骤:x成为y的左孩子,y的左孩子成为x的右孩子,x的左孩子和y的右孩子不变
*/
void RBTree::LeftRotate(Node *x)
{
Node *y=x->right;
x->right=y->left; //修改x的右孩子
y->left->parent=x; //修改y的左孩子的父节点
y->parent=x->parent;
if(x->parent==nil)
root=y;
else if(x==x->parent->left) //x为左孩子
x->parent->left=y;
else //x为右孩子
x->parent->right=y;
y->left=x;
x->parent=y;
}
/*
功能:右旋转
条件:x的左孩子不能为空
步骤:x成为y的右孩子,y的右孩子成为x的左孩子
说明:与左旋转对称
*/
void RBTree::RightRotate(Node *x)
{
Node *y=x->left;
x->left=y->right;
if (y->right!=nil)
y->right->parent=x;
y->parent=x->parent;
if(x->parent==nil)
root=y;
else if(x==x->parent->left)
x->parent->left=y;
else
x->parent->right=y;
y->right=x;
x->parent=y;
}
/*
功能:插入节点p时维护红黑树性质
说明:p的颜色为红色,所以p的父节点不能为红色
红黑树相关性质:(2)根结点是黑色的(改变)
(4)如果一个节点是红色的,那么他的两个子节点都是黑色的(改变)
(5)对每个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点(始终成立)
*/
void RBTree::InsertFixup(Node *p)
{
while(p->parent->color==RED) //p的父节点也是红色
if(p->parent==p->parent->parent->left) //如果p的父节点是左节点
{
Node *y=p->parent->parent->right; //y为p的叔节点
if(y->color==RED) //情况1:叔节点y为红色(与父节点在左或右无关)
{
p->parent->color=BLACK;
y->color=BLACK;
p->parent->parent->color=RED;
p=p->parent->parent;
}
else //叔结点y为黑色
{
if (p == p->parent->right) //情况2:p的叔结点y是黑色且p是一个右孩子(包括2种情况:父节点在左和右)
{
p = p->parent;
LeftRotate(p);
}
//Display();
p->parent->color=BLACK; //情况3:p的叔结点y是黑色且p是一个左孩子(方法:改变颜色做右旋)
p->parent->parent->color=RED;
RightRotate(p->parent->parent);
}
}
else if (p->parent == p->parent->parent->right) //如果p的父节点是右节点 //the same as above,exchange right and left
{
Node *y=p->parent->parent->left;
if(y->color==RED)
{
p->parent->color=BLACK;
y->color=BLACK;
p->parent->parent->color=RED;
p=p->parent->parent;
}
else
{
if (p == p->parent->left)
{
p = p->parent;
RightRotate(p);
}
p->parent->color=BLACK;
p->parent->parent->color=RED;
LeftRotate(p->parent->parent);
}
}
root->color = BLACK;
}
/*
功能:删除节点p时维护红黑树性质
问题:(1)如果y是原来的根结点,,而y的一个红色的孩子成为新的根结点,则违反了性质2
(2)如果x替换y后x和x-parent是红色的,则违反了性质4
(3)在树中移动y将导致先前包含y的任何路径上黑色结点个数少1
*/
void RBTree::DeleteFixup(Node *x)
{
while (x != root && x->color == BLACK)
{
if (x == x->parent->left)
{
Node *w = x->parent->right;
if (w->color == RED) //情况1:x的兄弟结点是红色的
{
x->parent->color = RED;
w->color = BLACK;
LeftRotate(x->parent);
w = x->parent->right; //设置新的w
}
else
{
if (w->right->color == BLACK && w->left->color == RED) //情况2:x的兄弟结点w是黑色,而w的两个子节点都是黑色
{
w->color = RED;
x->parent->color = BLACK;
x = x->parent;
}
else
{
if (w->right->color == RED) //情况3:x的兄弟w是黑色的,w的右孩子是黑色(w的左孩子是红色)。
{
w->color = BLACK;
w->left->color = RED;
RightRotate(w);
w = x->parent->right;
}
//情况3转换为情况4
//情况4:x的兄弟w是黑色的,且w的右孩子时红色的
w->color = x->parent->color;
x->parent->color = BLACK;
w->right->color = BLACK;
LeftRotate(x->parent);
x = root; //为了终止循环
}
}
}//if
else
{
Node *w = x->parent->left;
if (w->color == RED) //情况1:x的兄弟结点是红色的
{
x->parent->color = RED;
w->color = BLACK;
RightRotate(x->parent);
w = x->parent->left; //设置新的w
}
else
{
if (w->left->color == BLACK && w->right->color == RED) //情况2:x的兄弟结点w是黑色,而w的两个子节点都是黑色
{
w->color = RED;
//x->parent->color = BLACK;
x = x->parent;
}
else
{
if (w->left->color == RED) //情况3
{
w->color = BLACK;
w->right->color = RED;
LeftRotate(w);
w = x->parent->left;
}
//情况3转换为情况4
//情况4:x的兄弟w是黑色的,且w的右孩子时红色的
w->color = x->parent->color;
x->parent->color = BLACK;
w->left->color = BLACK;
RightRotate(x->parent);
x = root; //为了终止循环
}
}
}//else
}//while
x->color = BLACK; //如果X节点原来为红色,那么直接改为黑色
}
/*
功能:用另一棵子树替换一棵子树并成为其双亲(父节点)的孩子结点
输入参数:以v为根的子树替换以u为根的子树时,结点u的双亲变为结点v的双亲,并且最后v成为u的双亲的相应孩子
*/
void RBTree::Transplant(Node *u, Node *v)
{
if (u->parent == nil)
root = v;
else if (u == u->parent->left)
u->parent->left = v;
else
u->parent->right = v;
v->parent = u->parent;
}
/*构造函数*/
RBTree::RBTree()
{
nil=new Node;
nil->color=BLACK;
root=nil;
bHeight=0;
nodeNum=0;
}
/*销毁树,类似于析构函数,但是要手动调用*/
void RBTree::Destory(Node *p)
{
if(p==nil)
delete p;
else
{
Destory(p->left);
Destory(p->right);
delete p;
}
}
/*
功能:沿着某一结点,找到最小键值对应的结点
*/
Node *RBTree::Minimum(Node *x)
{
while (x->left != nil)
x = x->left;
return x;
}
/*
功能:沿着某一结点,找到最大键值对应的结点
*/
Node *RBTree::Maximum(Node *x)
{
while (x->right != nil)
x = x->right;
return x;
}
/*
功能:找到后继结点
说明:按中序遍历的次序查找后继,如果所有关键字都不同,则一个结点的后继是大于x->key的最小关键字的结点。即右子树中向左遍历,左孩子为nil的结点
*/
Node *RBTree::Successor(Node *x)
{
if (x->right != nil)
return Minimum(x->right);
Node *y = x->parent;
while (y != nil&&x == y->right)
{
x = y;
y = y->parent;
}
return y;
}
/*
功能:找到前继结点
说明:按中序遍历的次序查找前继,如果所有关键字都不同,则一个结点的后继是大于x-<key的最大关键字的结点。
*/
Node *RBTree::Predecessor(Node *x)
{
if (x->left != nil)
return Maximum(x->left);
Node *y = x->parent;
while (y != nil&&x == y->left)
{
x = y;
y = y->parent;
}
return y;
}
/*
功能:根据键值搜索树,返回指向找到结点的指针,找不到返回nil
输入参数:指向树根的指针x和关键字k;x的作用是迭代
*/
Node *RBTree::Search(Node *x,int k)
{
if (x == nil || k == x->key)
return x;
if (k < x->key)
return Search(x->left, k);
else
return Search(x->right, k);
}
/*
功能:插入一个节点
入口参数:节点p
说明:插入过程按普通二叉搜索树,调用InsertFixup()函数用来保持红黑树性质
*/
void RBTree::Insert(Node *z)
{
Node *p=new Node;
p=z;
p->color = RED;
if (root == nil)
{
p->parent = nil;
root = p;
}
else
{
Node *x = root;
Node *y = nil;
while (x != nil)
{
y = x; //最后y总为x的父节点
if (p->key<x->key)
x = x->left;
else
x = x->right;
}
p->parent = y; //这样,p就是x的兄弟
if (p->key<y->key)
y->left = p;
else
y->right = p;
}
p->left = nil;
p->right = nil;
nodeNum++;
InsertFixup(p);
}
/*
功能:删除一个结点,其键值k
入口参数:待删除的结点的键值
说明:删除后用DeleteFixup()来维护红黑树性质
*/
void RBTree::Delete(int k)
{
Node *z = Search(root, k);
Node *y = z;
Node *x = nil;
int oriColor = y->color; //y的最初颜色
if (z->left == nil)
{
x = z->right; //保存结点x的踪迹,最终移至结点y的原始位置上,指向y的唯一子节点或哨兵
Transplant(z,z->right);
}
else if (z->right == nil)
{
x = z->left;
Transplant(z,z->left);
}
else
{
y = Minimum(z->right);
oriColor = y->color;
x = y->right; //x为y的右孩子,不是z的
if (y->parent != z)
{
Transplant(y,y->right);
y->right = z->right;
y->right->parent = y;
}
Transplant(z,y);
y->left = z->left;
y->left->parent = y; //*
y->color = z->color; //最后把z的颜色赋给y,所以y的新位置不会出现两红情况
}
if (oriColor == BLACK) //如果y是红色,当y被删除或移动时,红黑性质依然保持
DeleteFixup(x);
}
void RBTree::Out(Node *p)
{
if(p!=nil)
{
Out(p->left);
cout << p->color << " " << p->ID << " " << p->key << endl;
Out(p->right);
}
}
void RBTree::Display()
{
cout<<"颜色 "<<"ID "<<"key"<<endl;
Out(root);
}
#endif
#include "RBTree.h"
int main()
{
Node node[11]={{10,"A"},{14,"B"},{4,"C"},{12,"D"},{11,"E"},{13,"F"},{7,"G"},{16,"H"},{65,"I"},{43,"J"},{98,"K"}};
Node node2[6] = { { 41 }, { 38 }, { 31 }, { 12 }, { 19 }, { 8 } };
RBTree tree1;
for (int i = 0; i < 11; i++)
{
tree1.Insert(node + i);
tree1.Display();
}
cout << "插入后:" << endl;
tree1.Display();
tree1.Delete(11);
cout << "删除后:" << endl;
tree1.Display();
tree1.Delete(43);
tree1.Display();
}