红黑树的插入和删除

RBTRee 插入节点:

  • 首先用BSTree的方法构造节点,然后创建一个真实的空节点,让所有没有真是子节点的节点都指向这个真实的空节点,而不是nullptr。插入之后的调平颜色和高度是问题的关键。
  • 以左子树为例,右子树为镜像操作。
  • 先找到叔伯节点,若叔伯节点不为空且颜色为红色,则父节点颜色改为黑色,叔伯节点变为黑色,爷爷节点变为红色,然后插入节点由原来的位置变成爷爷节点,然后向上回溯。这是一种情况。
  • 左边的直线插入 ‘ / ’ ,将父节点的颜色变为黑色,爷爷节点的颜色变成红色,然后进行一个右单旋转。如果是 ‘ < ’ 这种情况的内侧插入,先进行一个左单旋转,将其转化成 ‘ / ’ 这个情况,再进行一个右单旋转。
  • 调节到最后,将根节点变成黑色,即可。
bool RBTree<Type>::Insert(RBNode<Type>*& t, const Type& x)
{
	//按bst的规则插入节点
	RBNode<Type>* s = t;
	RBNode<Type>* pr = Nil;
	while (s != Nil)
	{
		if (s->data == x)
			return false;
		pr = s;
		if (s->data > x)
			s = s->leftChild;
		else
			s = s->rightChild;
	}
	//创建x值节点
	s = _Buynode(x);
	
	//插入节点
	if (pr == Nil)
		t = s; 
	else if (x < pr->data)
		pr->leftChild = s;
	else
		pr->rightChild = s;
	s->parent = pr;

	Insert_Fixup(t, s);
	return true;
}
void RBTree<Type>::Insert_Fixup(RBNode<Type>*& t, RBNode<Type>* x)
{
	while (x->parent->color == RED)
	{
		RBNode<Type>*s = Nil;
		if (x->parent == x->parent->parent->leftChild)//左分支
		{
			s = x->parent->parent->rightChild;//找到叔伯节点
			//3.
			if (s != Nil && s->color == RED)
			{
				x->parent->color = BLACK;
				s->color = BLACK;
				x->parent->parent->color = RED;
				x = x->parent->parent;
			}
			//2.内侧插入 拐弯插入  ‘<’
			else
			{
				if (x == x->parent->rightChild)  //先变成 ‘/’
				{
					//x->parent->parent->color = RED;
					//x->color = BLACK;
					x = x->parent;
					RotateL(t, x);
				}
				//1.直线插入  更改 PG的颜色  
				x->parent->color = BLACK;
				x->parent->parent->color = RED;
				RotateR(t, x->parent->parent);
			}
		}
		else//右分支
		{
			s = x->parent->parent->leftChild;//找到书博节点
			//3.
			if (s != Nil&&s->color == RED)
			{
				x->parent->color = BLACK;
				s->color = BLACK;
				x->parent->parent->color = RED;
				x = x->parent->parent;
			}
			else
			{
				//2.
				if (x == x->parent->leftChild)
				{
					x = x->parent;
					RotateR(t, x);
				}
				//1.
				x->parent->color = BLACK;
				x->parent->parent->color = RED;
				RotateL(t, x->parent->parent);
			}
		}
	}
	t->color = BLACK;
}

RBTree 删除节点的情况一共有六种:

1.被删除节点无子节点,且被删除节点为红色,则直接删除。

2.被删除节点无子节点,且被删除节点为黑色。

  1. *a1.如果它的兄弟节点为黑色,且兄弟节点存在和自己相同方向的子节点是红色(如果有子节点必然是红色),则进行左单旋转。

    a2.方向不同的红色子节点,双旋转。
    如果兄弟节点无子节点*

  2. *b1.兄弟节点没有子节点,父节点为红色,兄弟为黑色,将兄弟换成红色,父换成黑色

    b2.兄弟节点为红色,则父节点肯定为黑色,继续向上追溯,遇到别的情况直接进行调整*。

3.被删除节点有一个子节点,且被删除节点为红色。这个是不存在的,因为这样子不满足黑色分支都一样多。

4.被删除节点有一个子节点,且被删除为黑色,

5&6.被删除节点有两个子节点,且被删除节点为黑色或者红色,这种情况被转化成前面的1,2,4这三种之一。

所以删除只有三种大情况。

bool RBTree<Type>::Remove(RBNode<Type>*& t, const Type& key)
{
	RBNode<Type>*p = t, *c;  // c-----Child
	while (p != Nil)
	{
		if (p->data == key)
			break;
		if (key < p->data)
			p = p->leftChild;
		else
			p = p->rightChild;
	}
	if (p == Nil)
		return false;
	
	if (p->leftChild != Nil&&p->rightChild != Nil)
	{
		//找到要替换的值的节点位置
		RBNode<Type>*q;
		q = p->rightChild;
		while (q->leftChild != Nil)
			q = q->leftChild;

		p->data = q->data;
		p = q;
	}


	if (p->leftChild != Nil)
		c = p->leftChild;
	else
		c = p->rightChild;
	
	c->parent = p->parent;

	if (p->parent == Nil)//只有根节点的父不为空
		t = c;
	else if (p == p->parent->leftChild)
		p->parent->leftChild = c;
	else
		p->parent->rightChild = c;

	//调整平衡
	if (p->color == BLACK)
		Remove_fixup(t, c);


	delete p;
	return true;
}
/
template<class Type>
void RBTree<Type>::Remove_fixup(RBNode<Type>*& t, RBNode<Type>* x)
{
	RBNode<Type>* w;
	while (x != t && x->color == BLACK)
	{
		w = x->parent->rightChild;  //w是删除的节点的兄弟节点
		//第二大类的1 2 3
		if (x == x->parent->leftChild)//左边
		{
			//4.
			if (w->color == RED)
			{
				w->color = BLACK;
				x->parent->color = RED;
				w = w->leftChild;
				RotateL(t, x->parent);
			}
			//3.
			if (w->leftChild->color != RED&&w->rightChild->color != RED)
			{
				w->color = RED;
				x = x->parent;
			}
			else
			{

				//2.
				if (w->leftChild != Nil)//先将'>'变成 '\'
				{
					w->leftChild->color = BLACK;
					w->color = RED;
					w = w->leftChild;
					RotateR(t, w->parent);
				}
				//1.
				w->color = x->parent->color;
				x->parent->color = BLACK;
				w->rightChild->color = BLACK;
				RotateL(t, x->parent);
				x = t;
			}
		}
		else
		{
			//4.
			if (w->color == RED)
			{
				w->color = BLACK;
				x->parent->color = RED;
				w = w->rightChild;
				RotateR(t, x->parent);
			}
			//3.
			if (w->leftChild->color != RED&&w->rightChild->color != RED)
			{
				w->color = RED;
				x = x->parent;
			}
			else
			{

				//2.
				if (w->rightChild != Nil)//先将'>'变成 '\'
				{
					w->rightChild->color = BLACK;
					w->color = RED;
					w = w->rightChild;
					RotateL(t, w->parent);
				}
				//1.
				w->color = x->parent->color;
				x->parent->color = BLACK;
				w->leftChild->color = BLACK;
				RotateR(t, x->parent);
				x = t;
			}
		}
	}
	x->color = BLACK;
}

代码如上。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值