一、定义
1 节点 只有红 和 黑两种颜色
2 根节点是黑色的
3 红色节点的子节点必须为黑色
4 从每个节点到叶节点的路径上的黑色节点数都相等。
二、创建红黑树
2.1 插入新节点
可以分为以下的几种情况:
1. 插入节点的父节点为黑色 –> 直接插入,无需调整。
2. 插入节点的父节点为红色,分为 叔节点是黑色(NULL也看作是黑色) 和 红色 两种情况。
- 叔节点为黑色(或者是NULL) –> 根据内测插入和外侧插入 进行单旋转或者双旋转(和avl的旋转规则一样,旋转点是祖父节点),在把父节点变成黑色,祖父节点变成红色, 如祖父的父节点为也为红色,则继续向上调整(把祖父节点当做插入节点)。
- 叔节点为红色 –> 将父节点和叔节点都变成黑色, 祖父节点 变成红色, 如祖父的父节点为也为红色,则继续向上调整(把祖父节点当做插入节点)。
易错点: 在左旋和右旋的时候,要把旋转点的父节点搞清楚,不然旋转完后就接不上了。
2.2 删除节点
类比二叉查找树的删除,进行以下分类:
删除节点没有子节点
1 删除节点为黑色 –> 少了一个黑色(“双黑”节点)
2 删除节点为红色 –> 直接删除删除节点有 1 个子节点
1 删除节点为黑色,子节点为红色 –> 子节点补上,并将子节点变成黑色
2 删除节点为黑色,子节点为黑色 -->这种情况不存在
3 删除节点为红色,子节点为黑色 --> 这种情况也不存在删除节点有 2 个子节点
1 找左子树中最大的或者是右子树中最小的补上,再删除补上的点,这是就变成了上面两种情况了(有0个或1个子节点)
双黑节点的处理:
兄弟节点是黑色,并有红色子节点
1 左旋(双黑为左节点) ——(说明: 黄色A表示红黑均可,黑环B表示双黑) 当兄弟节点中远离B的子字节为红色时,采用左旋,旋转后C变成A的颜色,A->黑色,D–>黑色
2 右左旋(双黑为右结点) —— 当兄弟节点中靠近B的子字节为红色时,先将C右旋,再将A左旋,然后将D–> A的颜色,A–> 变成黑色。
3 右旋 —— 与左旋对称
4 左右旋 —— 与右左旋对称兄弟节点是红色,要么有两个黑色节点,要么没有节点
1 兄弟节点是红色,则父节点一定是黑色,将父节点进行左旋(双黑为左节点)或者右旋(双黑为右孩子),交换A和C的颜色,则此时B的兄弟节点就变成了黑色或者是NULL,就可以继续按其他的两种情况进行处理。
兄弟节点是黑色,没有红色子节点
1 父节点是红色 –> 将父节点变成黑色,兄弟节点变成红色
2 父节点是黑色 –> 将兄弟节点变红色,这时 父节点就变成了双黑,以父节点继续循环双黑处理
三、C++红黑树的实现
#include <iostream>
#include <algorithm>
#include <vector>
#include <deque>
using namespace std;
typedef struct rb_node{
int key;
int color;
struct rb_node* left;
struct rb_node* right;
struct rb_node* parent;
rb_node(int key, int color = 1,
struct rb_node* left = NULL, struct rb_node* right = NULL,
struct rb_node* parent = NULL):key(key),color(color){
this->left = left;
this->right = right;
this->parent = parent;
}
void SetNodeRed(){ this->color = 1;}
void SetNodeBlack(){ this->color = 0;}
int GetNodeColor() const{ return this->color;}
bool IsRed() const{ return (this == NULL) ? false : (this->color == 1);}
bool IsBlack() const{ return (this == NULL) ? true : (this->color == 0);}
} RBnode,*PRBnode;
PRBnode LeftRotate(PRBnode newNode, PRBnode& tree)
{
#if 0
if(newNode->parent != NULL){
if(newNode->key < newNode->parent->key){
newNode->parent->left = newNode->right;
}else{
newNode->parent->right = newNode->right;
}
}else{
root = newNode->right;
}
#endif
PRBnode tmp = newNode->right;
newNode->right = tmp->left;
if(tmp->left != NULL) tmp->left->parent = newNode;
tmp->left = newNode;
tmp->parent = newNode->parent;
newNode->parent = tmp;
if(tmp->parent != NULL){
if(tmp->key < tmp->parent->key){
tmp->parent->left = tmp;
}else{
tmp->parent->right = tmp;
}
}else{
//cout<<"===="<<endl;
tree = tmp;
}
return tmp;
}
PRBnode RightRotate(PRBnode newNode, PRBnode& tree)
{
#if 0
if(newnode->parent != NULL){
if(newnode->key < newnode->parent->key){
newnode->parent->left = newnode->left;
}else{
newnode->parent->right = newnode->left;
}
}else{
root = newnode->left;
}
#endif
PRBnode tmp = newNode->left;
newNode->left = tmp->right;
if(tmp->right != NULL) tmp->right->parent = newNode;
tmp->right = newNode;
tmp->parent = newNode->parent;
newNode->parent = tmp;
if(tmp->parent != NULL){
if(tmp->key < tmp->parent->key){
tmp->parent->left = tmp;
}else{
tmp->parent->right = tmp;
}
}else{
//cout<<"++++"<<endl;
tree = tmp;
}
return tmp;
}
void RBtreeFixup(PRBnode x, PRBnode& root)
{
if(x->parent->IsBlack()){
return;
}
while(x->IsRed() && x->parent->IsRed()){
PRBnode p = x->parent;
PRBnode g = p->parent;
PRBnode u = (p->key < g->key) ? g->right : g->left;
PRBnode gp = g->parent;
if(u->IsRed()){
x->SetNodeRed();
p->SetNodeBlack();
u->SetNodeBlack();
if(g->parent != NULL){
g->SetNodeRed();
if(g->parent->IsRed()){
x = g;
}
}
} else {
// 1. l
if(x == p->right && p == g->right){
x = LeftRotate(g, root);
x->SetNodeBlack();
x->left->SetNodeRed();
}
// 2. r
else if(x == p->left && p == g->left){
x = RightRotate(g,root);
x->SetNodeBlack();
x->right->SetNodeRed();
}
// 3. lr
else if(x == p->right && p == g->left){
LeftRotate(p,root);
x = RightRotate(g,root);
x->SetNodeBlack();
x->right->SetNodeRed();
}
// 4. rl
else if(x == p->left && p == g->right){
RightRotate(p,root);
x = LeftRotate(g,root);
x->SetNodeBlack();
x->left->SetNodeRed();
//p = x->parent;
}
}
}
}
PRBnode InsertNode(PRBnode root, int key)
{
// 1. It is a null tree
if(root == NULL){
root = new RBnode(key,0);
return root;
}
PRBnode tmp = root;
PRBnode p = root;
while(tmp != NULL){
p = tmp;
tmp = key < tmp->key ? tmp->left : tmp->right;
}
tmp = new RBnode(key, 1);
tmp->parent = p;
if(key < p->key){
p->left = tmp;
}else{
p->right = tmp;
}
RBtreeFixup(tmp, root);
return root;
}
void PrintTree(PRBnode root)
{
if(root == NULL){
return;
}
cout<<root->key<<"("<<root->color<<") ;";
PrintTree(root->left);
PrintTree(root->right);
}
void FreeNode(PRBnode& node)
{
if(node == NULL) return;
node->left = NULL;
node->right = NULL;
node->parent = NULL;
delete node;
node = NULL;
}
PRBnode FindMin(PRBnode root)
{
if(root == NULL) return NULL;
while(root->left) {
root = root->left;
}
return root;
}
#if 0
PRBnode DoubleBlack(PRBnode root)
{
if(root->parent == NULL){
FreeNode(root);
return NULL;
}
PRBnode tmp = root;
while(1){
if(root == root->parent->left){
PRBnode u = root->parent->right;
if(u->IsBlack()){ // u can not be null
if(u->right->IsRed()){
PRBnode x = LeftRotate(&(root->parent)); //??
x->color = x->left->color;
x->left->SetNodeBlack();
x->right->SetNodeBlack();
// FreeNode(root);
break;
} else if(u->left->IsRed()) {
RightRotate(&u);
PRBnode x = LeftRotate(&(root->parent));
x->color = x->left->color;
x->left->SetNodeBlack();
// FreeNode(root);
break;
} else{
if(root->parent->IsRed()){
root->parent->SetNodeBlack();
u->SetNodeRed();
break;
}else{
u->SetNodeRed();
if(root->parent->parent != NULL){
root = root->parent;
continue;
}else{
break;
}
}
}
}else{ // u is red
PRBnode x= LeftRotate(&(u->parent));
x->color = x->left->color;
x->left->SetNodeRed();
continue; //
}
}
if(root == root->parent->right){
PRBnode u = root->parent->left;
if(u->IsBlack()){ // u can not be null
if(u->left->IsRed()){
PRBnode x = RightRotate(&(root->parent)); //??
x->color = x->right->color;
x->right->SetNodeBlack();
x->left->SetNodeBlack();
// FreeNode(root);
break;
} else if(u->right->IsRed()) {
LeftRotate(&u);
PRBnode x = RightRotate(&(root->parent));
x->color = x->right->color;
x->right->SetNodeBlack();
// FreeNode(root);
break;
} else{
if(root->parent->IsRed()){
root->parent->SetNodeBlack();
u->SetNodeRed();
break;
}else{
u->SetNodeRed();
if(root->parent->parent != NULL){
root = root->parent;
continue;
}else{
break;
}
}
}
}else{ // u is red
PRBnode x= RightRotate(&(u->parent));
x->color = x->right->color;
x->right->SetNodeRed();
continue; //
}
}
}
FreeNode(tmp);
}
PRBnode DelNode(PRBnode root, int key)
{
if(root == NULL) return NULL;
if(key < root->key){
root->left = DelNode(root->left, key);
} else if(key > root->key){
root->right = DelNode(root->right, key);
} else {
if(root->left == NULL && root->right == NULL){
if(root->IsBlack()){
// fix
DoubleBlack(root);
} else {
//delete root;
//root = NULL;
FreeNode(root);
return NULL;
}
} else if(root->left != NULL && root->right == NULL){
if(root->IsRed()) {
cout<<"some error happen\n"<<endl;
return NULL;
}
if(root->left->IsRed()){
PRBnode tmp = root->left;
tmp->SetNodeBlack();
tmp->parent = root->parent;
if(root->parent != NULL){
root->parent->left = tmp;
}
FreeNode(root);
return tmp;
} else {
// no fix
// black node has a black node is impossible
}
} else if(root->left == NULL && root->right != NULL){
if(root->IsRed()) {
cout<<"some error happen\n"<<endl;
return NULL;
}
if(root->right->IsRed()){
PRBnode tmp = root->right;
tmp->SetNodeBlack();
tmp->parent = root->parent;
if(root->parent != NULL){
root->parent->right = tmp;
}
FreeNode(root);
return tmp;
} else {
// no fix;
// black node has a black node is impossible
}
}else{
PRBnode tmp = FindMin(root->right);
root->key = tmp->key;
DelNode(root->right, tmp->key);
}
}
}
#endif
PRBnode FindNode(PRBnode tree, int key)
{
if(tree == NULL) return NULL;
PRBnode tmp = tree;
while(key != tmp->key && tmp != NULL){
if(key < tmp->key)
tmp = tmp->left;
else if(key > tmp->key)
tmp = tmp->right;
}
return tmp;
}
void RebalanceDelete(PRBnode dbnode, PRBnode& tree)
{
if(dbnode->parent == NULL){
FreeNode(dbnode);
return;
}
while(dbnode && dbnode != tree){
PRBnode u = (dbnode == dbnode->parent->left)?dbnode->parent->right:dbnode->parent->left;
if(u->IsBlack()){
// u is black
if(dbnode == dbnode->parent->left){
if(u->right->IsRed()){
// ll
PRBnode x = LeftRotate(dbnode->parent, tree);
x->color = x->left->color;
x->left->SetNodeBlack();
x->right->SetNodeBlack();
break;
}else if(u->left->IsRed()){
//rl
RightRotate(u, tree);
PRBnode x = LeftRotate(dbnode->parent, tree);
x->color = x->left->color;
x->left->SetNodeBlack();
break;
}else{
// fix
u->SetNodeRed();
dbnode = dbnode->parent;
}
}else if(dbnode == dbnode->parent->right){
if(u->left->IsRed()){
//rr
PRBnode x = RightRotate(dbnode->parent, tree);
x->color = x->right->color;
x->left->SetNodeBlack();
x->right->SetNodeBlack();
break;
}else if(u->right->IsRed()){
//lr
LeftRotate(u, tree);
PRBnode x = RightRotate(dbnode->parent, tree);
x->color = x->right->color;
x->right->SetNodeBlack();
break;
}else{
// fix
u->SetNodeRed();
dbnode = dbnode->parent;
}
}
}else{
// u is red
if(dbnode == dbnode->parent->left){
// ll
LeftRotate(dbnode->parent, tree);
}else if(dbnode == dbnode->parent->right){
//rr
RightRotate(dbnode->parent, tree);
}
}
}
}
void DelNode(PRBnode& tree, int key)
{
cout<<"DelNode key = "<<key<<endl;
PRBnode delNode = FindNode(tree, key);
while(delNode != NULL){
if(delNode->left == NULL && delNode->right == NULL){
// has 0 child
if(delNode->IsRed()){
if(delNode->key < delNode->parent->key)
delNode->parent->left = NULL;
else
delNode->parent->right = NULL;
FreeNode(delNode);
}else{
// need fix
RebalanceDelete(delNode, tree);
if(delNode->key < delNode->parent->key)
delNode->parent->left = NULL;
else
delNode->parent->right = NULL;
FreeNode(delNode);
}
}else if(delNode->left == NULL || delNode->right == NULL){
// has 1 child
if(delNode->IsRed()){
cout<<"node color is error 1\n";
return;
}
PRBnode backup = (delNode->left == NULL)?delNode->right:delNode->left;
cout<<"backup = "<<backup->key<<" delnode = "<<delNode->key<<endl;
if(backup->IsBlack()) {
cout<<"node color is error 2\n";
return;
}
backup->SetNodeBlack();
if(delNode->key < delNode->parent->key)
delNode->parent->left = backup;
else
delNode->parent->right = backup;
backup->parent = delNode->parent;
FreeNode(delNode);
if(delNode == NULL) cout<<"delnode is null\n";
}else{
// has 2 childs
PRBnode backup = FindMin(delNode->right);
delNode->key = backup->key;
delNode = backup;
}
}
}
void PrintTreeRow(PRBnode root)
{
if(root == NULL) return;
deque<PRBnode> d;
PRBnode cur = NULL;
PRBnode last = root;
PRBnode nlast = NULL;
d.push_back(root);
while(!d.empty()){
cur = d.front();
if(cur != NULL){
cout<<cur->key<<"("<<cur->color;
if(cur->parent == NULL) cout<<" null)\t";
else cout<<" "<<cur->parent->key<<")\t";
} else{
cout<<"NULL\t";
}
d.pop_front();
if(cur->left){
d.push_back(cur->left);
nlast = cur->left;
}
if(cur->right){
d.push_back(cur->right);
nlast = cur->right;
}
if(last == cur){
cout<<endl;
last = nlast;
}
}
cout<<"===================\n";
}
int main()
{
int b[7] = {10,50,30,13,60,45,12};
vector<int> a(b,b+7);
int c[6] = {35,55,70,80,23,24};
a.insert(a.end(),c,c+6);
#if 1
for(int j=0; j<a.size(); j++){
cout<<a[j]<<"; ";//<<endl;
// cout<<(void*)&(a[j])<<endl;
}
cout<<endl;
#endif
PRBnode root = NULL;
for(int i = 0; i < a.size(); i++){
root = InsertNode(root,a[i]);
#if 0
cout<<a[i]<<endl;
PrintTree(root);
cout<<endl;
PrintTreeRow(root);
#endif
}
PrintTreeRow(root);
PrintTree(root);
cout<<endl;
//PrintTreeRow(root);
DelNode(root,45);
PrintTree(root);
cout<<endl;
PrintTreeRow(root);
return 0;
}