1,红黑树的定义
1,)红黑树的每个节点不是红色就是黑色。
2)根节点是黑色的
3)如果节点是红色的,其子节点必定是黑色的
4)任一节点至NULL(树尾端)的任何路径,所包含的黑节点数必相同
2,红黑树的插入操作(下面的是作者自己的理解,讲述的不清楚,原理的详细描述请看https://www.jianshu.com/p/e136ec79235c)
插入操作分为两步进行,第一步插入(和二叉搜索树的插入是一样的,这里不再讲述,插入的时候把节点颜色设置成红色),第二步调整使插入后,满足红黑树的定义。
- 调整策略
1)当插入节点的不存在父节点时(即插入的节点就是根节点),将插入节点的颜色设置成黑色
2)当插入节点的父节点的颜色是黑色的时候,不进行调整就符合红黑树的性质。
3)当插入节点的父节点是红色的情况时需要使用函数void insertAdjust(rbNode<T>* root)进行调整,这个函数的含义是因为root处多了红色节点需要进行调整,是的整个树满足红黑树的性质。这个时候就需要区分当root的父节点在祖父节点的左子树还是右子树,其中4),5),6)以root的父节点在祖父节点的左子树为例进行讲解。
4)当root的叔叔节点存在且为红色的时候,这个时候把root的父节点和叔叔节点的颜色设置成黑色,把root的祖父节点设置成黑色,然后对root的祖父节点执行insertAdjust(root -> parent -> parent)操作。
5)当root的叔叔节点不存在或者是黑色的时候,且root节点是其父节点的左孩子,这个时候把root的父节点设置成黑色,root的祖父节点设置成红色,对root的祖父节点执行右旋操作即可。
6)当root的叔叔节点不存在或者是黑色的时候,且root节点是其父节点的右孩子,这个时候先对root的右结点执行左旋操作,然后就变成了5)所述的情况,在执行一次右旋操作即可。
3,红黑树的删除操作(下面的是作者自己的理解,讲述的不清楚,原理的详细描述请看https://www.cnblogs.com/tongy0/p/5460623.html)
- 删除操作分为四种情况:
情况一:删除的节点的左、右子树都非空;
情况二:删除的节点的左子树为空树,右子树非空;
情况三:删除的节点的右子树为空树,左子树非空;
情况四:删除的节点的左、右子树都为空树;
注意作者自己的代码实现思路是,首先找到删除的节点位置,后面三种情况删除的是需要删除的val的位置pos,而第一种情况删除的是val的后继结点的位置pos,找到需要删除的位置(del)之后,还要确定需要替补pos位置的节点(把替补节点命名为delchild),肯定是pos的一个孩子结点,只有第二种情况delchild = del -> left,其余的情况都是delchild = del -> right;这里需要连接好del的父节点和delchild的指针(特殊的情况是del即树根节点)。如果del的颜色是红色直接删除del,否则,需要执行deleteAdjust(delchild, del);操作,这个操作的含义是调整由于以delchild为根节点的红黑树所拥有的黑节点数目比以delchild的兄弟节点为根节点的红黑树所拥有的黑节点数目少1造成的不平衡。注意在执行这条语句之前,已经把del节点从红黑树上摘下(还没有delete)之所以把del作为第二个参数的主要作用是因为del里面有delchild父节点(将del摘下后,delchild的父节点就是原del的父节点)的信息。之所以有第二个参数,是因为delchild可能是NULL,这个时候del的作用通过它获得delchild的父节点。
删除操作在进行调整的时候的思路是先自己解决,自己解决不了,找兄弟借红节点,兄弟解决不了交给父母找远方亲戚解决。
- 自己解决的情况
当delchild是红色的,把delchild的颜色设置成黑色即可
- 找兄弟借红节点(以delchild在其父节点的左子树为例)
1)delchild的兄弟结点是红色的情况(这种情况变换后成为哪种情况都有可能)
把delchild的父节点设置成红色,把delchild的兄弟结点设置成黑色,对delchild的父节点进行左旋操作,然后在对delchild进行deleteAdjust(delchild, del)操作,因为这个时候delchild的兄弟结点变成了黑色的
2)delchild的兄弟结点是黑色的,并且兄弟结点的右孩子不空且为红色的
把delchild的兄弟结点的右孩子的颜色设置成黑色的,把兄弟结点的颜色设置成delchild的父节点的颜色,把delchild的父节点设置成黑色的,对delchild的父节点进行左旋转操作
3)delchild的兄弟结点是黑色的,并且兄弟结点的左孩子是红色的,右孩子是黑色的(右孩子是红色的会进入第二种情况),这个时候先把delchild兄弟节点的左孩子变成黑色的,再把delchild的兄弟节点变成红色的,对delchild的兄弟节点进行右旋操作,此时变成了2),这个时候在执行deleteAdjust(delchild, del)就可以达到平衡
- 找父亲帮忙向远方亲戚借红节点
这个时候是delchild的兄弟节点是黑色的,且它不存在红色的子节点,这个时候就必须通过父亲帮忙。执行下面的操作,
将delchild的兄弟节点设置成红色的,然后执行deleteAdjust(delchild -> parent, delchild -> parent)进行调整即可,注意这里的第二个参数(结合前面介绍的第二个参数的含义理解,其中就是需要第二个参数中所包含的父节点的信息)。
4,红黑树的代码
#include <iostream>
using namespace std;
enum Color{Red, Black};
template <typename T>
struct rbNode{
T data;
Color color;
rbNode<T>* left;
rbNode<T>* right;
rbNode<T>* parent;
rbNode(T val, Color _color):data(val), color(_color), left(NULL), right(NULL), parent(NULL){}
};
template <typename T>
class rbTree{
private:
rbNode<T>* root;
public:
rbTree(){ root = NULL; }
~rbTree(){clean();}
rbNode<T>*& getRoot(){return root;}//获得rb树的树根指针
void leftRotate(rbNode<T>* &root);//左旋
void rightRotate(rbNode<T>* &root);//右旋
void preOrder(const rbNode<T>* root) const;
void inOrder(const rbNode<T>* root) const;
void clean(rbNode<T>* &root); //delete掉new出来的空间
void insert(rbNode<T>* &root, T val, rbNode<T>* parent = NULL);//在以root为根节点的子树插入节点val
void insertAdjust(rbNode<T>* root);//调整因为root处的红节点而出现的不平衡情况
void deleteVal(T val);
rbNode<T>* findValPos(T val);//找到val的位置
rbNode<T>* findMaxNextPos(rbNode<T>* root);//找到最大后继结点的位置
void deleteAdjust(rbNode<T>* root, rbNode<T>* del);//调整因为删除root结点的父节点造成的黑结点个数少1的问题
};
template <typename T>
void rbTree<T>::preOrder(const rbNode<T>* root) const{
if(root != NULL){
cout << root -> data << " " << root -> color << endl;
preOrder(root -> left);
preOrder(root -> right);
}
}
template <typename T>
void rbTree<T>::inOrder(const rbNode<T>* root) const{
if(root != NULL){
inOrder(root -> left);
cout << root -> data << " " << root -> color << endl;
inOrder(root -> right);
}
}
template <typename T>
void rbTree<T>::clean(rbNode<T>* &root){
if(root != NULL){
clean(root -> letf);
clean(root -> right);
delete root;
}
}
template <typename T>
void rbTree<T>::insert(rbNode<T>* &root, T val, rbNode<T>* parent){
if(root == NULL){
root = new rbNode<T>(val, Red);
root -> parent = parent;
insertAdjust(root);
return;
}
if(root -> data < val){
insert(root -> right, val, root);
}else{
insert(root -> left, val, root);
}
}
template <typename T>
void rbTree<T>::leftRotate(rbNode<T>* &root){
rbNode<T>* rootright = root -> right;
rbNode<T>* rootparent = root -> parent;
rootright -> parent = rootparent;
if(rootparent != NULL){//当root不为根节点的时候
if(rootparent -> left == root){
rootparent -> left = rootright;
}else{
rootparent -> right = rootright;
}
}else{
this -> root = rootright;
}
root -> parent = rootright;
root -> right = rootright -> left;
if(root -> right != NULL)
root -> right -> parent = root;
rootright -> left = root;
root = rootright;
}
template <typename T>
void rbTree<T>::rightRotate(rbNode<T>* &root){
rbNode<T>* rootleft = root -> left;
rbNode<T>* rootparent = root -> parent;
rootleft -> parent = rootparent;
if(rootparent != NULL){//当root不为根节点的时候
if(rootparent -> left == root){
rootparent -> left = rootleft;
}else{
rootparent -> right = rootleft;
}
}else{
this -> root = rootleft;
}
root -> parent = rootleft;
root -> left = rootleft -> right;
if(root -> left != NULL)
root -> left -> parent = root;
rootleft -> right = root;
root = rootleft;
}
template <typename T>
void rbTree<T>::insertAdjust(rbNode<T>* root){
if(root -> parent == NULL){
root -> color = Black;
return;
}
if(root -> parent -> color == Black){
return ;
}
//插入节点的父节点是红色的情况
rbNode<T>* parent = root -> parent;
rbNode<T>* grandP = root -> parent -> parent;
if(grandP -> left == parent){//插入节点在祖父节点的左子树
rbNode<T>* uncle = grandP -> right;
if(uncle != NULL && uncle -> color == Red){
parent -> color = Black;
uncle -> color = Black;
grandP -> color = Red;
insertAdjust(grandP);
}else{
if(parent -> right == root){
leftRotate(parent);
}
rightRotate(grandP);//注意函数定义的形参是引用
grandP -> color = Black;
grandP -> right -> color = Red;
}
}else{//插入节点在祖父节点的右子树
rbNode<T>* uncle = grandP -> left;
if(uncle != NULL && uncle -> color == Red){
parent -> color = Black;
uncle -> color = Black;
grandP -> color = Red;
insertAdjust(grandP);
}else{
if(parent -> left == root){
rightRotate(parent);
}
leftRotate(grandP);
grandP -> color = Black;
grandP -> left -> color = Red;
}
}
}
template <typename T>
void rbTree<T>::deleteVal(T val){
rbNode<T>* pos = findValPos(val);
if(pos == NULL){
return;
}
rbNode<T>* del = NULL;
if(pos -> left == NULL || pos -> right == NULL){
del = pos;
}else{
del = findMaxNextPos(pos);
pos -> data = del -> data;
}
//执行删除操作前需要把树连接好
rbNode<T>* delchild = NULL;//delchild是代替结点的位置
delchild = (del -> left != NULL ? del -> left : del -> right);
if(del -> parent != NULL){
if(delchild != NULL)//代替的节点有可能是空的
delchild -> parent = del -> parent;
if(del -> parent -> left == del){
del -> parent -> left = delchild;
}else if(del -> parent -> right == del){
del -> parent -> right = delchild;
}
}else{//删除是树根节点的时候,需要重新设置树根节点
this -> root = delchild;
}
if(del -> color == Black){//删除结点是红色的时候不需要调整
deleteAdjust(delchild, del);
}
delete del;
}
template <typename T>
rbNode<T>* rbTree<T>::findMaxNextPos(rbNode<T>* root){
root = root -> right;
if(root == NULL)
return NULL;
while(root -> left != NULL){
root = root -> left;
}
return root;
}
template <typename T>
rbNode<T>* rbTree<T>::findValPos(T val){
rbNode<T>* trans = getRoot();
while(trans != NULL && trans -> data != val){
if(trans -> data < val){
trans = trans -> right;
}else{
trans = trans -> left;
}
}
return trans;
}
template <typename T>
void rbTree<T>::deleteAdjust(rbNode<T>* root, rbNode<T>* del){
if(root != NULL && (root == this -> root || root -> color == Red)){//root结点自己就可以解决平衡
root -> color = Black;
return;
}
rbNode<T>* rootParent = del -> parent;
rbNode<T>* rootBrother = NULL;
rbNode<T>* rootBrotherLeftChild = NULL;
rbNode<T>* rootBrotherRightChild = NULL;
if(rootParent -> left == root){
rootBrother = rootParent -> right;
rootBrotherLeftChild = rootBrother -> left;
rootBrotherRightChild = rootBrother -> right;
if(rootBrother -> color == Red){
rootParent -> color = Red;
rootBrother -> color = Black;
leftRotate(rootParent);
deleteAdjust(root, del);
}else{
if(rootBrotherRightChild != NULL && rootBrotherRightChild -> color == Red){//右红
rootBrotherRightChild -> color = Black;
rootBrother -> color = rootParent -> color;
rootParent -> color = Black;
leftRotate(rootParent);
}else if(rootBrotherLeftChild != NULL && rootBrotherLeftChild -> color == Red){//左红右黑
rootBrotherLeftChild -> color = Black;
rootBrother -> color = Red;
rightRotate(rootBrother);
deleteAdjust(root, del);
}else{
rootBrother -> color = Red;
deleteAdjust(rootParent, rootParent);
}
}
}else{
rootBrother = rootParent -> left;
rootBrotherLeftChild = rootBrother -> left;
rootBrotherRightChild = rootBrother -> right;
if(rootBrother -> color == Red){
rootParent -> color = Red;
rootBrother -> color = Black;
rightRotate(rootParent);
deleteAdjust(root, del);
}else{
if(rootBrotherLeftChild != NULL && rootBrotherLeftChild -> color == Red){//左红
rootBrotherLeftChild -> color = Black;
rootBrother -> color = rootParent -> color;
rootParent -> color = Black;
rightRotate(rootParent);
}else if(rootBrotherRightChild != NULL && rootBrotherRightChild -> color == Red){//左黑右红
rootBrotherRightChild -> color = Black;
rootBrother -> color = Red;
leftRotate(rootBrother);
deleteAdjust(root, del);
}else{
rootBrother -> color = Red;
deleteAdjust(rootParent, rootParent);
}
}
}
}
int main(){
int a;
rbTree<int> *myRBTree = new rbTree<int>;
while(cin >> a){
if(a == 0){
break;
}
myRBTree -> insert(myRBTree -> getRoot(), a);
}
myRBTree -> preOrder(myRBTree -> getRoot());
cout << "中序遍历" <<endl;
myRBTree -> inOrder(myRBTree -> getRoot());
while(cin >> a){
if(a == 0) break;
myRBTree -> deleteVal(a);
myRBTree -> preOrder(myRBTree -> getRoot());
cout << "中序遍历" <<endl;
myRBTree -> inOrder(myRBTree -> getRoot());
}
return 0;
}