红黑的插入

定义

红黑树是一种二叉搜索树
每个结点上增加一个存储位表示结点的颜色,可以是Red或Black 通过对任何一条从根到叶子的路径上各个结点着色方式的限制。

红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的。
红黑树是如何保证该核心属性的呢?
通过下列五个性质

性质

  1. 每个结点不是红色就是黑色
  2. 根节点是黑色的
  3. 如果一个节点是红色的,则它的两个孩子结点是黑色的
  4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均 包含相同数目的黑色结点
  5. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点,即NIL节点)
    在这里插入图片描述

通过上述性质,红黑树很好的实现了没有一条路径比其他路径长两倍

没有一条路径比其他路径长两倍也可以为以下含义
红黑树中最长路径的长度不能超过最短路径的两倍
性质1,2,5是红黑树的基本性质,需要满足。没什么要讨论的。
性质3与4是解决长度问题的关键

性质3. 如果一个节点是红色的,则它的两个孩子结点是黑色的
也可以理解为 不能出现两个连续的红节点

性质4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均 包含相同数目的黑色结点

性质3与4结合来看
首先每条路径上黑节点的数目要一致,红色节点不能连着出现

当一条路径最短时,节点均为黑色;
当一条路径最长时,每个黑节点下均链接着红色节点
MAX = 2*MIN;
也就是满足了
红黑树中最长路径的长度不能超过最短路径的两倍

插入

红黑树的插入大体部分与AVL树相近,但调整时有所不同
插入的返回值时一个键值对
当插入成功时 iterator 指向插入的节点 , bool值为true
拆入失败时,即该树中已经存在该元素,iterator为原有节点,bool值为false

	std::pair<iterator,bool> Insert(const ValueType& data)
	{
		//判断是否为空树,为空树创建第一个节点
		if (_pHead == nullptr)
		{
			_pHead = new Node(data, BLACK);
			return std::make_pair(iterator(_pHead),true);
		}
		//按照二叉搜索树的规则进行插入
		//从根节点开始查找位置,根节点的父节点为nullptr
		pNode parent = nullptr;
		pNode cur = _pHead;
		//当cur指向空时,当前位置即是目标位置
		while (cur)
		{
			//parent在查询元素目标位置的过程中,
			//一定会指向cur的位置
			parent = cur;

			//二叉树具有排异性,当树中存在相同元素时,不能再插入
			if (KeyOfValue(cur->_data) == KeyOfValue(data))
			{
				return pair(cur, false);
			}
			else if (KeyOfValue(cur->_data) < KeyOfValue(data))
			{
				cur = cur->_pRight;
			}
			else
			{
				cur = cur->_pLeft;
			}
		}
		//进行元素的插入
		cur = new Node(data);
		cur->_pParent = parent;
		if (KeyOfValue(cur->_data) > KeyOfValue(parent->_data))
		{
			parent->_pRight = cur;
		}
		else
		{
			parent->_pLeft = cur;
		}
		pNode cur_copy = cur;
		//红黑树的调整
		//uncle
		// uncle = cur == parent->_pLeft ? parent->_pRight : parent->_pLeft;
		while (parent && parent->_pParent && parent->_color == RED)
		{
			pNode grand = parent->_pParent;
			//parent在左侧
			if (parent == grand->_pLeft)
			{
				pNode uncle = grand->_pRight;
				//情况二与三
				if (uncle == nullptr || uncle->_color == BLACK)
				{
					//异侧情况三
					if (cur == parent->_pRight)
					{
						RotateL(parent);
						std::swap(parent, cur);

					}
					//情况二
					RotateR(grand);
					parent->_color = BLACK;
					grand->_color = RED;
					
					if (cur == _pHead)
						cur->_color = BLACK;
					break;
				}
				//情况一
				else
				{
					uncle->_color = parent->_color = BLACK;
					//grand为根时 直接置为黑
					if (grand == _pHead)
					{
						grand->_color = BLACK;
						break;
					}
					else
					{
						grand->_color = RED;
						cur = grand;
						parent = cur->_pParent;
					}

				}
			}
			//parent在右侧
			else
			{
				pNode uncle = grand->_pLeft;
				//情况二与三
				if (uncle == nullptr || uncle->_color == BLACK)
				{
					//异侧情况三
					if (cur == parent->_pLeft)
					{
						RotateR(parent);
						std::swap(parent, cur);

					}
					//情况二

					RotateL(grand);
					parent->_color = BLACK;
					grand->_color = RED;
					
					if (cur == _pHead)
						cur->_color = BLACK;
					break;
				}
				//情况一
				else
				{
					uncle->_color = parent->_color = BLACK;
					//grand为根时 直接置为黑
					if (grand == _pHead)
					{
						grand->_color = BLACK;
						break;
					}
					else
					{
						grand->_color = RED;
						cur = grand;
						parent = cur->_pParent;
					}

				}
			}
		}
		return std::make_pair(iterator(cur_copy), true);
	}

调整

调整红黑树的前提是,插入破坏了红黑树的结构
新节点的默认颜色是红色,只有当双亲节点为红色时才破坏了红黑树的结构
当新插入节点的双亲节点颜色为红色时,就违反了性质三不能有连在一起的红色节点,此时需要对红黑树分情况来讨论:

红黑树的调整可以分为3中情况
以单侧举例
约定:cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点
情况一: cur为红,p为红,g为黑,u存在且为红
在这里插入图片描述
解决方式:将p,u改为黑,g改为红,然后把g当成cur,继续向上调整。
情况二: cur为红,p为红,g为黑,u不存在/u存在且为黑
在这里插入图片描述
说明: u的情况有两种
1.如果u节点不存在,则cur一定是新插入节点,因为如果cur不是新插入节点则cur和p一定有一个节点的颜色是黑色,就不满足性质4: 每条路径黑色节点个数相同。
2.如果u节点存在,则其一定是黑色的,那么cur节点原来的颜色一定是黑色的现在看到其是红色的原因是因为cur的子树在调整的过程中将cur节点的颜色由黑色改成红色。
解决方案
p为g的左孩子,cur为p的左孩子,则进行右单旋转
p、g变色–p变黑,g变红

情况三: cur为红,p为红,g为黑,u不存在/u存在且为黑
在这里插入图片描述
p为g的左孩子,cur为p的右孩子,则针对p做左单旋转。后转为情况二

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值