RedBlackTree(红黑树)

目录

一、概念

二、RBTreeNode

三、插入

情况一:uncle存在且为红色

情况二:uncle不存在或者uncle存在且为黑

四、红黑树的验证


一、概念

        1.一棵树是红黑树的前提是这棵树是二叉搜索树

        2.红黑树的结点不是红色就是黑色

        3.红黑树中最长路径不超过最短路径的两倍

        红黑树底层封装了map和set,这足以说明红黑树的优劣,而红黑树超高的效率的核心:

        1.红黑树中根结点是黑色

        2.红黑树中不存在连续的红色结点

        3.红黑树的每一条路径所含有的黑色结点数量相同

        满足这三点,即可满足最长路径不超过最短路径的两倍。

        对上述要点作以下说明:

        1.红黑树中最长路径不超过最短路径的两倍,假设最短路径为h,那么其他路径的长度就是[h,2h]。极端情况下,最短路径都是黑色结点,不存在红色结点,最长路径是一黑一红的黑红相间,但是,一棵红黑树不一定存在最长路径和最短路径,也有可能是平衡的。

        2.红黑树中不存在连续的红色结点。一个红色结点的孩子必然是黑色,一个黑色结点的孩子可以是红色也可以是黑色。

二、RBTreeNode

enum Color
{
	RED,
	BLACK
};
template <class K,class V>
struct RBTreeNode
{
	typedef RBTreeNode<K, V> Node;

	Node* _left;
	Node* _right;
	Node* _parent;
	enum Color _col;

	pair<K, V> _kv;

	RBTreeNode(const pair<K, V>& kv)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _kv(kv)
		,col(RED)
	{}
};

三、插入

        在写出代码之前,先对插入的各类情况分析。

        插入新结点的颜色必须是红色,如果插入新节点的颜色是黑色,则大概率会违反红黑树的每一条路径所含有的黑色结点数量相同”。

        在插入结点是红色结点后,插入结点的parent结点如果是黑色,则不需要调整,当前状态一定符合红黑树的规则。

        如果插入结点的parent结点是红色,则需要分情况处理,这部分也是红黑树最为关键的部分。且插入结点的grandfather结点一定是黑色(在插入结点之前的树一定是红黑树,说明不存在连续的红色结点)。

        插入结点cur ——红色

        插入结点的parent —— 红色

        插入结点的grandfather —— 黑色

        插入结点的uncle ——???

    根据uncle的不同而做不同的插入处理

情况一:uncle存在且为红色

        处理方式:

parent 和 uncle 由 RED - 》 BLACK

grandfather 由 BLACK - 》 RED

如果grandfather是根结点,则还原为黑色

如果grandfather不是根结点,则让cur == grandfather,继续向上处理。

        在情况一中,parent、uncle、cur是left还是right都不影响处理的结果,处理的方式都是一样的

        

情况二:uncle不存在或者uncle存在且为黑

         如果uncle不存在,则cur一定为新增结点。

        处理方式:

        如果p是g的左孩子,cur是p的左孩子,则右单旋

        如果p是g的右孩子,cur是p的右孩子,则左单旋

        然后变色:g由黑变红,p由红变黑

        

        如果p是g的左孩子,cur是p的右孩子,则左右双旋,然后变色:g由黑变红,cur由红变黑

        如果p是g的右孩子,cur是p的左孩子,则右左双旋,然后变色

         如果uncle存在且为黑色结点,则cur一定不是新增结点,而是由原来的黑色结点经过情况一的处理变出来的红色结点。此时的处理情况也是旋转+变色。

        和情况一不同的是,情况二经过旋转+变色,无论是p变为黑色结点还是cur变为黑色结点,都不需要再向上处理。

        基于以上分析,红黑树的插入代码实现如下:

    bool Insert(const pair<K, V>& kv)
	{
        //按照二叉搜索树插入
		if (_root == nullptr)
		{
			_root = new Node(kv);
			_root->_col = BLACK;
			return true;
		}
		Node* cur = _root;
		Node* parent = nullptr;
		while (cur)
		{
			if (kv.first < cur->_kv.first)
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (kv.first > cur->_kv.first)
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				//说明要插入的值已经存在了,提升插入失败
				return false;
			}
		}

		cur = new Node(kv);
		if (kv.first > parent->_kv.first)
		{
			parent->_right = cur;
		}
		else
		{
			parent->_left = cur;
		}
		cur->_parent = parent;

		//红黑树的处理
		while (parent && parent->_col == RED)
		{
			Node* grandfather = parent->_parent;
			if (parent == grandfather->_left)
			{
                //情况一:uncle存在且为红
				Node* uncle = grandfather->_right;
				if (uncle && uncle->_col == RED)
				{
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;

					cur = grandfather;
					parent = cur->_parent;
				}
				else
				{
                    //情况二:uncle不存在或者uncle存在且为黑
					if (cur == parent->_left)
					{
						//右单旋+变色
						RotateR(grandfather);
						grandfather->_col = RED;
						parent->_col = BLACK;
					}
					else
					{
						//左右单旋+变色
						RotateL(parent);
						RotateR(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}
					break;
				}
			}
			else
			{
                //情况一
				Node* uncle = grandfather->_left;
				if (uncle && uncle->_col == RED)
				{
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;

					cur = grandfather;
					parent = cur->_parent;
				}
				else
				{
                    //情况二
					if (cur == parent->_right)
					{
						//左单旋+变色
						RotateL(grandfather);
						grandfather->_col = RED;
						parent->_col = BLACK;
					}
					else
					{
						//右左单旋+变色
						RotateR(parent);
						RotateL(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}
					break;
				}
			}
		}

		_root->_col = BLACK;
		return true;
	}

四、红黑树的验证

        验证红黑树即验证下面这三点:

          红黑树中根结点是黑色

          红黑树中不存在连续的红色结点

          红黑树的每一条路径所含有的黑色结点数量相同

//balcknum表示从根结点到当前结点这条路径的黑色结点个数
	bool Check(Node* cur,int blacknum,int RefBlackNum)
	{
		if (cur == nullptr)
		{
			if (blacknum != RefBlackNum)
			{
				cout << "每条路径黑色结点不相同" << endl;
				return false;
			}
			cout <<"这条路径有黑色结点个数" <<  blacknum << endl;
			return true;
		}
			
		if (cur->_col == RED && cur->_parent->_col == RED)
		{
			cout << "存在连续的红色结点" << endl;
			return false;
		}
		if (cur->_col == BLACK)
			blacknum++;
		return Check(cur->_left,blacknum,RefBlackNum) && Check(cur->_right,blacknum,RefBlackNum);
	}
	bool IsRBTree()
	{
		//验证根结点是否是黑色
		if (_root && _root->_col == RED)
			return false;

		//求出一条路径上的黑色结点作参考,这里求出最左路径上的黑色结点
		int RefBlackNum = 0;
		Node* cur = _root;
		while (cur)
		{
			if (cur->_col == BLACK)
				++RefBlackNum;
			cur = cur->_left;
		}
		return Check(_root,0,RefBlackNum);
	}

        用以下代码测试实现的红黑树:

#include "RBTree.h"
void testRBTree1()
{
	RBTree<int, int> t;
	//int arr[] = { 4,2,16, 3, 7, 11, 9, 26, 18, 14, 15 ,2 };
	int arr[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16,14 };
	for (auto e : arr)
	{
		t.Insert(make_pair(e, e));
	}
	t.InOrder();
	cout << t.IsRBTree() << endl;
}
int main()
{
	testRBTree1();

	return 0;
}

        运行结果:

        完整代码 红黑树

        模拟STL源码,用KV模型的红黑树封装map和setgitee代码链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值