红黑树简单讲解

1.红黑树的概念 


红黑树是一棵二叉搜索树,他的每个结点增加一个存储位来表示结点的颜色,可以是红色或者黑色。
通过对任何一条从根到叶子的路径上各个结点的颜色进行约束,红黑树确保没有一条路径比其他路径长出2倍,因而是接近平衡的。



1.1 红黑树的规则:

红黑树的一切都是围绕这4点构建的:


1.每个结点不是红色就是黑色
2.根结点是黑色的
3.如果一个结点是红色的,则它的两个孩子结点必须是黑色的,也就是说任意一条路径不会有连续的红色结点。

4.对于任意一个结点,从该结点到其所有NULL结点的简单路径上,均包含相同数量的黑色结点

只要满足上面4点条件 就一定会有没有一条路径 会 比其他路径 长出2倍以上。

理论相差最长路径:

右边最多为四个节点,左边最少两个节点。

理论最长路径:比如:


2.红黑树的插入(我们只需要学会这个就行,结尾有总代码)

我们先按照二叉搜索树的规则插入节点:

新增结点标识为c (cur),c的父亲标识为p(parent),p的父亲标识为g(grandfather),p的兄弟标识为u(uncle)。

我们可以分为两大类:

1.第一大类:

叔叔(uncle)存在,并且叔叔(uncle)为红。

这种情况我们只需要变色 + 向上处理,就可以了:

把parent 和 uncle 变为黑色, 把 grandfather 变为红色 

再把 cur 变为 grandfather 继续向上更新。

代码为:


3. 第二大类 :

叔叔(uncle)不存在 或者 叔叔(uncle)为黑色

第二大类分为两个小类:


3.1第二大类的第一小类:

这里我们统一以左子树为例子(右子树同理)

1.cur 插入 在 parent 的左边

如图所示:

假设我们 没插入节点之前 的树 如图所示:

插入 cur 节点:

 插入后,按照第一大类调整:

把 parent 变黑  , 把 grandfather 变红 ,再把 grandfather 进行右旋转

代码为:


问题:为什么不需要向上更新了(parent如上图)?

没有连续的红色结点了,且不需要往上更新,因为:父亲(parent)是黑色,上面的节点无论是红色或者空都不违反规则。


3.2第二大类的第二小类:

        我们统一以左子树为例子(右子树同理)

1.cur 插入在 parent 的 右边 如图所示:

原图

cur 是按 第一大类 更新上来的:

我们以 parent作为旋转点 进行左旋转,再以 grandfather作为旋转点 进行右旋转,最后把 cur变为黑色,grandfather 变为红。


问题:为什么不需要向上更新了(cur如上图)?

没有连续的红色结点了,且不需要往上更新,因为:cur 是黑色,上面的节点无论是红色或者空都不违反规则。


总代码:

	bool Insert(const T& data)
			{
				Node* cur = _pHead;
				Node* parent = nullptr;
				if (cur == nullptr)
				{
					_pHead = new Node(data);
				}
				else
				{
					while (cur)
					{
						if (cur->_k < data)
						{
							parent = cur;
							cur = cur->_pRight;
						}
						else if (cur->_k > data)
						{
							parent = cur;
							cur = cur->_pLeft;
						}
						else
						{
							assert(false);
						}
					}

					cur = new Node(data);
					if (cur->_k < parent->_k)
						parent->_pLeft = cur;
					else
						parent->_pRight = cur;
					cur->_parent = parent;

					//上方为插入节点
					/
					while (parent && parent->cl == RED)
					{
						Node* uncle = nullptr;
						Node* grandfather = parent->_parent;
						//左边 
						if (grandfather && parent == grandfather->_pLeft)
						{
							uncle = grandfather->_pRight;

							if (uncle && uncle->cl == RED)
							{
								parent->cl = BLACK;
								uncle->cl = BLACK;
								grandfather->cl = RED;
							}
							else
							{
								if (cur == parent->_pLeft)
								{

									RotateR(grandfather);
									parent->cl = BLACK;
									grandfather->cl = RED;
								}
								else
								{

									RotateL(parent);
									RotateR(grandfather);
									grandfather->cl = RED;
									cur->cl = BLACK;

								}
								break;
							}
							cur = grandfather;
							parent = cur->_parent;
						}
						//右边
						else if (grandfather && parent == grandfather->_pRight)
						{
							uncle = grandfather->_pLeft;

							if (uncle && uncle->cl == RED)
							{
								parent->cl = BLACK;
								uncle->cl = BLACK;
								grandfather->cl = RED;

							}
							else
							{
								if (cur == parent->_pRight)
								{
									parent->cl = BLACK;
									grandfather->cl = RED;
									RotateL(grandfather);
								}
								else
								{
									grandfather->cl = RED;
									cur->cl = BLACK;
									RotateR(parent);
									RotateL(grandfather);

								}
							}
							cur = grandfather;
							parent = cur->_parent;
						}

					}

				}
				_pHead->cl = BLACK;
				return true;
			}

左右单旋:

// 左单旋
			void RotateL(Node * pParent)
			{
				Node* RChild = pParent->_pRight;
				Node* RLChild = RChild->_pLeft;
				Node* grandfather = pParent->_parent;

				if (RLChild)
					RLChild->_parent = pParent;
				pParent->_pRight = RLChild;

				RChild->_pLeft = pParent;
				pParent->_parent = RChild;
				RChild->_parent = grandfather;

				if (grandfather == nullptr)
				{
					_pHead = RChild;
				}
				else
				{
					if (grandfather->_pLeft == pParent)
						grandfather->_pLeft = RChild;
					else if (grandfather->_pRight == pParent)
						grandfather->_pRight = RChild;

				}
			}
			// 右单旋
			void RotateR(Node * pParent)
			{
				Node* LChild = pParent->_pLeft;
				Node* LRChild = LChild->_pRight;
				Node* grandfather = pParent->_parent;

				if (LRChild)
					LRChild->_parent = pParent;
				pParent->_pLeft = LRChild;

				LChild->_pRight = pParent;
				pParent->_parent = LChild;
				LChild->_parent = grandfather;

				if (grandfather == nullptr)
				{
					_pHead = LChild;
				}
				else
				{
					if (grandfather->_pLeft == pParent)
						grandfather->_pLeft = LChild;
					else if (grandfather->_pRight == pParent)
						grandfather->_pRight = LChild;

				}
			}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值