红黑树插入删除操作

红黑树有以下的性质:

性质1. 节点是红色或黑色。

性质2. 根节点是黑色。

性质3 每个叶节点(NIL节点,空节点)是黑色的。

性质4 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)

性质5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

红黑树是二叉平衡树的一种、STL中的map、set、xxxmap、xxxset都是使用红黑树来完成的。它可以在O(log n)时间内做查找,插入和删除,这里的n 是树中元素的数目。

我就不画图了,网上可以搜到很多:红黑树删除操作

插入操作


回到正题:先开始插入操作(不要紧张、让我们慢慢将它理清)

X当前要插入的节点、P父亲、G祖父、GG曾祖、S叔叔:(新节点都是红色的)

情况一:根节点为空

            X直接成为根节点、改变颜色为黑。

情况二:P为黑色

            X直接插入、什么也不用做

情况三:P为红色

            1.S为黑色

             1.1 X为外侧插入:改变P G颜色 G旋转

                   P为G左、X为P左  : G右旋(当然是改变颜色之后)

                   P为G右、X为P右  : G左旋

              1.2 X为内侧插入:P 旋转 改变X G颜色 G旋转(为什么这次改变的是X的颜色而不是P、因为旋转后X就会到达上面P的位置、说白了内侧插入的处理方式就是将其转化成外侧插入再处理。)

                   P为G左、X为P右  : P 左旋 变颜色 G右旋

                   P为G右、X为P左  : P 右旋 变颜色 G左旋

            2.S为红色

             2.1 X为外侧插入:G旋转 改变X颜色

                   P为G左、X为P左  :G右旋

                   P为G右、X为P右  :G左旋

              2.2 X为内侧插入:P X旋转、改变P颜色、G旋转

                   P为G左、X为P右  :P 左旋 变颜色 G右旋

                   P为G右、X为P右  :P 右旋 变颜色 G左旋

注意:当S为红色时、在进行上面所说的操作之后、要进行判断、如果GG( 要注意旋转之后节点之间关系的变化 )为红色则以当前这棵小树的根节点为X重新判定。

掌握了关键的判定点整个插入操作就有了框架、至于没有图。。。自己去搜吧(有很多、对照着看)

其实插入还是比较简单的、很多情况的处理方法都差不多、内侧插入的情况都是先转化为外侧情况 再做的。

我直接把删除也说了吧、然后代码一起贴上

删除操作


X 要删除节点、P父亲、G祖父、S兄弟、N原节点

N原节点:在删除节点的时候、都会选择key对应位置的节点的右子树中最小的节点F(右子树的最左侧)或左子树中最大的节点E(左子树的最右侧)来替换当前key对应的节点、实际上删除的是F/E、将F/E的value赋给N节点、这里N就是原节点、而X是真正删除的节点。

情况一:X为根节点

            直接删除、根节点赋空

情况二:X为红色节点

            如果它是红色节点一定没有孩子的、直接删除 (别忘了对N进行赋值和对应位置赋空(它父亲的这个孩子没了 要赋空))

情况三:X为黑色节点

            1.X有一个红孩子(不需考虑其他情况、如果有孩子、只能是一个、只能是红色、这是红黑树性质决定的)

               用红孩子节点替换X的位置( 是替换、将X节点摘除 )、赋值给N、删除X

            2.X没有孩子:X是一个黑色叶子节点

               2.1 S为黑色

                   2.1.1 S有一个红孩子(先判断外侧孩子、如果外侧孩子不是红色、则将内侧孩子旋转成外侧的)

                             X为P左、侄为S右:P S颜色互换、侄变黑、左旋P、删除、结束

                             X为P右、侄为S左:                                       右旋P、

                             X为P左、侄为S左:S 侄 颜色互换、右旋S 情况转到上面

                             X为P右、侄为S右:                          左旋S

                   2.1.2 S没有孩子:S是一个黑色叶子节点

                             P为红:P S 颜色互换、删除、结束

                             P为黑:S 变红 、直接删除、结束

                2.2 S为红色

                       P S 颜色互换

                       X为P左:左旋P

                       X为P右:右旋P

 

注意:在操作时、不要忘记将N进行赋值、和对删除位置的替换或赋空。

下面见代码:

我将所有操作封在一个类中、插入删除操作重点看insert_cal()、erase()

一些操作确实复杂、但是红黑树值得我们 沉下心来 认真学习

#pragma once
#include <cstdio>
#include <cstdlib>
#include <string>
using namespace std;
template<class KEY,class VAL>
class CMyRBTree
{
private:
	struct RBT
	{
		KEY		key;
		VAL		value;
		char	color;
		RBT*	parent;
		RBT*	lchild; 
		RBT*	rchild;
		RBT(KEY k,VAL v):key(k),value(v),color('r'),parent(0),
		lchild(0),rchild(0){}
	};
	RBT*	root;
public:
	CMyRBTree(void);
	~CMyRBTree(void);
private:
	void	rotate_node_left(RBT* node);		//左旋
	void	rotate_node_right(RBT* node);		//右旋
	void	insert_cal(RBT* node);				//插入节点后需要进行调整
	RBT*	_find(KEY key);						//查找
	void	_release(RBT** root);				//使用后序递归删除所有节点
	void	truncateNode(RBT* node);			//对要删除节点的对应位置赋空
	void	deleteNode(RBT** node,RBT* top);	//删除节点、对原节点赋值
public:
	bool	insert(KEY key,VAL val);
	bool	erase(KEY key);
	bool	find(KEY key,VAL& val);	
	bool	release();
};


template<class KEY,class VAL>
CMyRBTree<KEY,VAL>::CMyRBTree(void):root(0)
{
}

template<class KEY,class VAL>
CMyRBTree<KEY,VAL>::~CMyRBTree(void)
{
	release();
}

template<class KEY,class VAL>
void	CMyRBTree<KEY,VAL>::rotate_node_left(RBT* node)
{
	if(node == NULL || root == NULL)
		return;
	RBT* mark = node->rchild;
	if(node->parent){
		if(node == node->parent->lchild)
			node->parent->lchild = mark;
		else
			node->parent->rchild = mark;
	}else{//node为根节点、所以要对根节点指针重新赋值
		root = mark;
		root->color = 'b';
	}
	mark->parent = node->parent;
	node->parent = mark;

	node->rchild = mark->lchild;
	mark->lchild = node;
	if(node->rchild)
		node->rchild->parent = node;
}
template<class KEY,class VAL>
void	CMyRBTree<KEY,VAL>::rotate_node_right(RBT* node)
{
	if(node == NULL || root == NULL)
		return;
	RBT* mark = node->lchild;
	if(node->parent){
		if(node == node->parent->lchild)
			node->parent->lchild = mark;
		else
			node->parent->rchild = mark;
	}else{
		root = mark;
		root->color = 'b';
	}
	mark->parent = node->parent;
	node->parent = mark;

	node->lchild = mark->rchild;
	mark->rchild = node;
	if(node->lchild)
		node->lchild->parent = node;
}

template<class KEY,class VAL>
void	CMyRBTree<KEY,VAL>::insert_cal(RBT* node)
{
	if(node == NULL)
		return;
	RBT* ptmp = NULL;	//叔叔
	while(1)
	{
		if(node->parent == NULL){//根节点为空
			node->color = 'b';
			root = node;
			break;
		}
		if(node->parent->color == 'b'){//父节点为红色直接插入
			break;
		}else{
			if(node->parent->parent->lchild == node->parent)
				ptmp = node->parent->parent->rchild;
			else
				ptmp = node->parent->parent->lchild;
			if(ptmp == NULL || ptmp->color == 'b')
			{//S为黑色
				if(node->parent == node->parent->parent->lchild)
				{//P是G的左孩子
					if(node == node->parent->lchild)
					{//X是P的左孩子
						node->parent->color = 'b';
						node->parent->parent->color = 'r';
						rotate_node_right(node->parent->parent);
						break;
					}else{//X是P的右孩子
						node->color = 'b';
						node->parent->parent->color = 'r';
						rotate_node_left(node->parent);
						rotate_node_right(node->parent);
						break;
					}
				}else{//P是G的右孩子
					if(node == node->parent->rchild)
					{//X是P的右孩子
						node->parent->color = 'b';
						node->parent->parent->color = 'r';
						rotate_node_left(node->parent->parent);
						break;
					}else{//X是P的左孩子
						node->color = 'b';
						node->parent->parent->color = 'r';
						rotate_node_right(node->parent);
						rotate_node_left(node->parent);
						break;
					}
				}
			}
			else
			{//S节点为红色
				if(node->parent == node->parent->parent->lchild)
				{//P是G的左孩子
					if(node == node->parent->lchild)
					{
						node->color = 'b';
						rotate_node_right(node->parent->parent);
						//调整节点重新判定
						node = node->parent;
					}else{
						node->parent->color = 'b';
						rotate_node_left(node->parent);
						rotate_node_right(node->parent);
					}
				}else{
					if(node == node->parent->rchild)
					{
						node->color = 'b';
						rotate_node_left(node->parent->parent);
						node = node->parent;
					}else{
						node->parent->color = 'b';
						rotate_node_right(node->parent);
						rotate_node_left(node->parent);
					}
				}
			}
		}
	}
}

template<class KEY,class VAL>
bool	CMyRBTree<KEY,VAL>::insert(KEY key,VAL val)
{
	RBT* node = new RBT(key,val);
	if(root == NULL)
	{
		root = node;
		root->color = 'b';
		return true;
	}
	RBT* ptmp = root;
	while(1)
	{
		if(key > ptmp->key)
		{
			if(ptmp->rchild)
				ptmp = ptmp->rchild;
			else{
				ptmp->rchild = node;
				node->parent = ptmp;
				insert_cal(node);
				break;
			}
		}else if(key < ptmp->key)
		{
			if(ptmp->lchild)
				ptmp = ptmp->lchild;
			else{
				ptmp->lchild = node;
				node->parent = ptmp;
				insert_cal(node);
				break;
			}
		}else{//这里重复插入则、只改变value值
			ptmp->value = val;
			delete node;
			node = NULL;
			break;
		}
	}
	return true;
}

template<class KEY,class VAL>
void	CMyRBTree<KEY,VAL>::truncateNode(RBT* node)
{
	if(node && node->parent){
		if(node == node->parent->lchild)
			node->parent->lchild = NULL;
		else
			node->parent->rchild = NULL;
	}
}

template<class KEY,class VAL>
void	CMyRBTree<KEY,VAL>::deleteNode(RBT** node,RBT* top)
{
	if(*node == NULL)
		return;
	if(top){
		top->key =  (*node)->key;
		top->value = (*node)->value;
	}
	delete *node;
	*node = NULL;
}

template<class KEY,class VAL>
bool	CMyRBTree<KEY,VAL>::erase(KEY key)
{
	RBT* node = _find(key);
	if(node == NULL)
		return false;
	RBT* ptmp = NULL;
	if(node->rchild){
		ptmp = node->rchild;
		if(ptmp->lchild)
			while(ptmp->lchild->lchild)
				ptmp = ptmp->lchild;
	}else if(node->lchild){
		ptmp = node->lchild;
		if(ptmp->rchild)
			while(ptmp->rchild->rchild)
				ptmp = ptmp->rchild;
	}else{//node原节点是叶子节点
		ptmp = node;
	}
	//删除根节点
	if(ptmp->parent == NULL){
		deleteNode(&ptmp,NULL);
		root = NULL;
	}
	RBT* pbrother = NULL;	//兄弟节点
	if(ptmp == ptmp->parent->lchild)
		pbrother = ptmp->parent->rchild;
	else
		pbrother = ptmp->parent->lchild;
	while(1)
	{
		if(ptmp->color == 'r')
		{//X为红色
			truncateNode(ptmp);
			deleteNode(&ptmp,node);
			break;
		}else{//X为黑色节点
			if(ptmp->lchild || ptmp->rchild)
			{//有一个红孩子(如果有,只能有一个孩子、也只能是红色)
				if(ptmp->lchild){
					ptmp->lchild->color = 'b';
					ptmp->lchild->parent = ptmp->parent;
					if(ptmp == ptmp->parent->lchild)
						ptmp->parent->lchild = ptmp->lchild;
					else
						ptmp->parent->rchild = ptmp->lchild;
					deleteNode(&ptmp,node);
					break;
				}else{
					ptmp->rchild->color = 'b';
					ptmp->rchild->parent = ptmp->parent;
					if(ptmp == ptmp->parent->lchild)
						ptmp->parent->lchild = ptmp->rchild;
					else
						ptmp->parent->rchild = ptmp->rchild;
					deleteNode(&ptmp,node);
					break;
				}
			}else
			{//X为黑色叶子节点/此时pbrother节点一定不为空
				if(pbrother->color == 'b')
				{//兄弟节点为黑色
					if((pbrother->rchild && pbrother->rchild->color == 'r')
						||(pbrother->lchild && pbrother->lchild->color == 'r'))
					{//S至少有一个红孩子
						if(pbrother->rchild && 
							pbrother->rchild->color == 'r')
						{
							if(ptmp == ptmp->parent->lchild){
								pbrother->color = ptmp->parent->color;
								ptmp->parent->color = 'b';
								pbrother->rchild->color = 'b';
								rotate_node_left(ptmp->parent);
								truncateNode(ptmp);
								deleteNode(&ptmp,node);
								break;
							}else{
								pbrother->color = 'r';
								pbrother->rchild->color = 'b';
								rotate_node_left(pbrother);
								if(ptmp == ptmp->parent->lchild)
									pbrother = ptmp->parent->rchild;
								else
									pbrother = ptmp->parent->lchild;
								//进入下一次判定
							}
						}else{
							if(ptmp == ptmp->parent->rchild)
							{
								pbrother->color = ptmp->parent->color;
								ptmp->parent->color = 'b';
								rotate_node_right(ptmp->parent);
								truncateNode(ptmp);
								deleteNode(&ptmp,node);
								break;
							}else{
								pbrother->color = 'r';
								pbrother->lchild->color = 'b';
								rotate_node_right(pbrother);
								if(ptmp == ptmp->parent->lchild)
									pbrother = ptmp->parent->rchild;
								else
									pbrother = ptmp->parent->lchild;
								//进入下一次判定
							}
						}
					}else{//
						if(pbrother->lchild == NULL && pbrother->rchild == NULL)
						{//S为黑色叶子节点
							if(ptmp->parent->color == 'r')
							{//P为红色
								pbrother->color = ptmp->parent->color;
								ptmp->parent->color = 'b';
								truncateNode(ptmp);
								deleteNode(&ptmp,node);
								break;
							}else{
								pbrother->color = 'r';
								truncateNode(ptmp);
								deleteNode(&ptmp,node);
								break;
							}
						}
					}
				}
				//S节点为红色
				else
				{
					pbrother->color = ptmp->parent->color;
					ptmp->parent->color = 'r';
					if(ptmp == ptmp->parent->lchild){
						rotate_node_left(ptmp->parent);
					}else{
						rotate_node_right(ptmp->parent);
					}

					//调整pbrother指针、进入下一次判定
					if(ptmp == ptmp->parent->lchild)
						pbrother = ptmp->parent->rchild;
					else
						pbrother = ptmp->parent->lchild;
				}
			}
		}
	}
	return true;
}

template<class KEY,class VAL>
typename CMyRBTree<KEY,VAL>::RBT*	CMyRBTree<KEY,VAL>::_find(KEY key)
{
	if(root == NULL)
		return NULL;
	RBT* ptmp = root;
	while(1)
	{
		if(key > ptmp->key)
		{
			if(ptmp->rchild)
				ptmp = ptmp->rchild;
			else
				return NULL;
		}else if(key < ptmp->key)
		{
			if(ptmp->lchild)
				ptmp = ptmp->lchild;
			else
				return NULL;
		}else
			return ptmp;
	}
	return NULL;
}

template<class KEY,class VAL>
bool	CMyRBTree<KEY,VAL>::find(KEY key,VAL& val)
{
	RBT* node = _find(key);
	if(node == NULL)
		return false;
	val = node->value;
	return true;
}

template<class KEY,class VAL>
void	CMyRBTree<KEY,VAL>::_release(RBT** root)
{
	if(*root == NULL)
		return ;
	_release(&(*root)->lchild);
	_release(&(*root)->rchild);
	delete *root;
	*root = NULL;
}

template<class KEY,class VAL>
bool	CMyRBTree<KEY,VAL>::release()
{
	_release(&root);
	return true;
}

文章如有错误之处、欢迎指正。。。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值