红黑树——RBTree

红黑树的概念:

红黑树,是一种二叉搜索树,但是**在每个节点上增加一个存储位表示节点的颜色,可以是red或者black。**通过对任何一条从根到叶子的路径上各个节点着色方式的限制,红黑树确保没有一条路径会比其他路径长出两倍,因而是接近平衡的。
在这里插入图片描述

红黑树的性质

  1. 每个节点不是红色就是黑色
  2. 根节点是黑色
  3. 如果一个节点是红色,则它的两个孩子节点是黑色(没有连续的两个红色节点)
  4. 对于每个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点个数
  5. 每个叶子节点都是黑色

为什么满足上面的性质,红黑树就能保证,最长路径中的节点个数不会超过最短路径上节点数的两倍?
原因:因为红黑树是用颜色来保持平衡的,而且红色节点不能连续,并且从根节点到任意一个叶子节点其路径上的黑色节点个数都相等

红黑树节点的定义

//红黑树结点的定义
template<class K, class V>
struct RBTreeNode
{
	//三叉链
	RBTreeNode<K, V>* _left;
	RBTreeNode<K, V>* _right;
	RBTreeNode<K, V>* _parent;

	//存储的键值对
	pair<K, V> _kv;

	//结点的颜色
	int _col; //红/黑

	//构造函数
	RBTreeNode(const pair<K, V>& kv)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _kv(kv)
		, _col(RED)
	{}
};

红黑树的插入

按照二叉搜索树规则对新节点进行插入
//插入函数
	pair<Node*, bool> Insert(const pair<K, V>& kv)
	{
		if (_root == nullptr) //若红黑树为空树,则插入结点直接作为根结点
		{
			_root = new Node(kv);
			_root->_col = BLACK; //根结点必须是黑色
			return make_pair(_root, true); //插入成功
		}
		//1、按二叉搜索树的插入方法,找到待插入位置
		Node* cur = _root;
		Node* parent = nullptr;
		while (cur)
		{
			if (kv.first < cur->_kv.first) //待插入结点的key值小于当前结点的key值
			{
				//往该结点的左子树走
				parent = cur;
				cur = cur->_left;
			}
			else if (kv.first > cur->_kv.first) //待插入结点的key值大于当前结点的key值
			{
				//往该结点的右子树走
				parent = cur;
				cur = cur->_right;
			}
			else //待插入结点的key值等于当前结点的key值
			{
				return make_pair(cur, false); //插入失败
			}
		}

		//2、将待插入结点插入到树中
		cur = new Node(kv); //根据所给值构造一个结点
		Node* newnode = cur; //记录新插入的结点(便于后序返回)
		cur->colour=RED;
		if (kv.first < parent->_kv.first) //新结点的key值小于parent的key值
		{
			//插入到parent的左边
			parent->_left = cur;
			cur->_parent = parent;
		}
		else //新结点的key值大于parent的key值
		{
			//插入到parent的右边
			parent->_right = cur;
			cur->_parent = parent;
		}

检查新节点的插入是否破坏红黑树原有的性质

因为新节点的默认颜色是红色,因此:如果其双亲节点的颜色是黑色,没有违反红黑树的任何规则。但是当其双亲节点是红色时,就违反了性质三。需要对该树进行调整

插入场景
  1. parent是黑色,插入新节点后不需要进行调整,插入结束
  2. parent是红色,违反规则三,需要分情况进行处理:

cur——》当前节点
p——》父节点
g——》祖父节点
u——》叔叔节点
情况一:cur为红,p为红,g为黑,u存在且为红

在这里插入图片描述
解决方案:p和u变黑,将g变红,然后继续往上处理(因为有可能祖父的父亲节点是红色),停止条件是p存在且为黑或者p不存在(将根变为黑,因为当前位置,cur是根,但是默认cur为红)
情况二:cur为红,p为红,g为黑,u不存在或者u存在且为黑(g、p、cur在一条直线上)
在这里插入图片描述
解决方案:旋转+变色(上图是:右单旋+p变黑,g变红)
情况三:情况二:cur为红,p为红,g为黑,u不存在或者u存在且为黑(g、p、cur为之字形)
在这里插入图片描述
解决方案:
当u不存在时:p为旋转点进行左单旋,然后再以g为旋转点进行右单旋,cur变黑,g变红。
当u存在且为黑时:以p为旋转点进行左旋,将cur的左作为p的右,然后以g为旋转点进行右单旋,将cur的右作为g的左,然后将cur变黑g变红。

//3、若插入结点的父结点是红色的,则需要对红黑树进行调整
		while (parent&&parent->_col == RED)
		{
			Node* grandfather = parent->_parent; //parent是红色,则祖父节点一定存在,因为根必须是黑色,所以肯定是有祖父节点
			//关键看叔叔
			if (parent == grandfather->_left) //parent是grandfather的左孩子
			{
				Node* uncle = grandfather->_right; //uncle是grandfather的右孩子
				//情况一:把p、u变黑,g变红
				if (uncle&&uncle->_col == RED) //情况1:uncle存在且为红
				{
					//颜色调整
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;

					//继续往上处理
					cur = grandfather;
					parent = cur->_parent;
				}
				else //情况2+情况3:uncle不存在 + uncle存在且为黑
				{
					//情况二:单旋
					if (cur == parent->_left)
					{
						RotateR(grandfather); //右单旋

						//颜色调整
						grandfather->_col = RED;
						parent->_col = BLACK;
					}
					else //cur == parent->_right
					{
						//RotateL(parent);
						//RotateR(grangfather);
						RotateLR(grandfather); //左右双旋

						//颜色调整
						grandfather->_col = RED;
						cur->_col = BLACK;
					}
					break; //子树旋转后,该子树的根变成了黑色,无需继续往上进行处理
				}
			}
			else //parent是grandfather的右孩子
			{
				Node* uncle = grandfather->_left; //uncle是grandfather的左孩子
				if (uncle&&uncle->_col == RED) //情况1:uncle存在且为红
				{
					//颜色调整
					uncle->_col = parent->_col = BLACK;
					grandfather->_col = RED;

					//继续往上处理
					cur = grandfather;
					parent = cur->_parent;
				}
				else //情况2+情况3:uncle不存在 + uncle存在且为黑
				{
					if (cur == parent->_left)
					{
						RotateRL(grandfather); //右左双旋

						//颜色调整
						cur->_col = BLACK;
						grandfather->_col = RED;
					}
					else //cur == parent->_right
					{
						RotateL(grandfather); //左单旋

						//颜色调整
						grandfather->_col = RED;
						parent->_col = BLACK;
					}
					break; //子树旋转后,该子树的根变成了黑色,无需继续往上进行处理
				}
			}
		}
		_root->_col = BLACK; //根结点的颜色为黑色(可能被情况一变成了红色,需要变回黑色)
		return make_pair(newnode, true); //插入成功
	}
查找
//查找函数
	Node* Find(const K& key)
	{
		Node* cur = _root;
		while (cur)
		{
			if (key < cur->_kv.first) //key值小于该结点的值
			{
				cur = cur->_left; //在该结点的左子树当中查找
			}
			else if (key > cur->_kv.first) //key值大于该结点的值
			{
				cur = cur->_right; //在该结点的右子树当中查找
			}
			else //找到了目标结点
			{
				return cur; //返回该结点
			}
		}
		return nullptr; //查找失败
	}

拷贝树(深拷贝)
//拷贝树
	Node* _Copy(Node* root, Node* parent)
	{
		if (root == nullptr)
		{
			return nullptr;
		}
		Node* copyNode = new Node(root->_data);
		copyNode->_parent = parent;
		copyNode->_left = _Copy(root->_left, copyNode);
		copyNode->_right = _Copy(root->_right, copyNode);
		return copyNode;
	}
析构函数的子函数
//析构函数子函数
	void _Destroy(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
		_Destroy(root->_left);
		_Destroy(root->_right);
		delete root;
	}

左单旋

//左单旋
	void RotateL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;
		Node* parentParent = parent->_parent;

		//建立subRL与parent之间的联系
		parent->_right = subRL;
		if (subRL)
			subRL->_parent = parent;

		//建立parent与subR之间的联系
		subR->_left = parent;
		parent->_parent = subR;

		//建立subR与parentParent之间的联系
		if (parentParent == nullptr)
		{
			_root = subR;
			_root->_parent = nullptr;
		}
		else
		{
			if (parent == parentParent->_left)
			{
				parentParent->_left = subR;
			}
			else
			{
				parentParent->_right = subR;
			}
			subR->_parent = parentParent;
		}
	}

	

右单旋

//右单旋
	void RotateR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
		Node* parentParent = parent->_parent;

		//建立subLR与parent之间的联系
		parent->_left = subLR;
		if (subLR)
			subLR->_parent = parent;

		//建立parent与subL之间的联系
		subL->_right = parent;
		parent->_parent = subL;

		//建立subL与parentParent之间的联系
		if (parentParent == nullptr)
		{
			_root = subL;
			_root->_parent = nullptr;
		}
		else
		{
			if (parent == parentParent->_left)
			{
				parentParent->_left = subL;
			}
			else
			{
				parentParent->_right = subL;
			}
			subL->_parent = parentParent;
		}
	}

双旋

	//左右双旋
	void RotateLR(Node* parent)
	{
		RotateL(parent->_left);
		RotateR(parent);
	}

	//右左双旋
	void RotateRL(Node* parent)
	{
		RotateR(parent->_right);
		RotateL(parent);
	}

	Node* _root; //红黑树的根结点
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值