红黑树原理及代码实现

17 篇文章 0 订阅

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;
}

 

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值