红黑树的平衡

1.红黑树的概念

红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或
Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路
径会比其他路径长出俩倍
,因而是接近平衡的。

 

2.红黑树的性质 

1. 每个结点不是红色就是黑色
2. 根节点是黑色的 
3. 如果一个节点是红色的,则它的两个孩子结点是黑色的 (没有连续的红色节点)
4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均 包含相同数目黑色结点 
5. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)NIF节点
思考:为什么满足上面的性质,红黑树就能保证:其最长路径中节点个数不会超过最短路径节点
个数的两倍?看图

路径:从该节点到NIF节点

最短路径:全黑节点

最长路径:一黑一红

 3.红黑树的平衡

节点定义

enum Color
{
	RED,
	BLACK,
};

template<class K,class V>
class RBNode
{
public:
	typedef RBNode<K, V> Node;

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

	Node* _left;
	Node* _right;
	Node* _parent;
	Color _col;
	pair<K, V> _kv;//库里面提供的结构体,表示key和value

};

颜色初始化必须是红色,如果插入的是黑色,必定会影响每条路径的黑色节点的数量,红色的话只会影响该条路径

插入


template<class K,class V>
class RBTree
{
public:
	typedef RBNode<K, V> Node;
	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 (parent->_kv.first > kv.first)
		{
			parent->_left = cur;
		}
		else
		{
			parent->_right = cur;
		}
		cur->_parent = parent;

        //...........
     }

private:
	Node* _root = nullptr;
};

插入分为三种情况(p为parent,g为grandparent,u为uncle)

cur一定为红色了

1:p是黑色,不用处理

2:p是红色,u存在且为红色

3:p是红色,u不存在或存在为黑色

情况2: 

p是红色,u存在且为红色

变色+向上

 

情况3:

 p是红色,u不存在或存在为黑色

u在右孩子时

u在左孩子同理 

下面是插入后面实现的代码,里面有注释

            while(parent&&parent->_col == RED)
		    {
				Node* grandparent = parent->_parent;
				if (grandparent->_right == parent)
				{
					Node* uncle = grandparent->_left;
					//情况1:u存在且为红,变色加向上调整
					if (uncle && uncle->_col == RED)
					{
						parent->_col = BLACK;
						uncle->_col = BLACK;
						grandparent->_col = RED;

						//向上调整
						cur = grandparent;
						parent = cur->_parent;
					}
					else//情况2a:u不存在或者u存在且为黑  旋转+变色
					{
						/*    g
                           u     p
								   c*/
						//左单旋+变色
						if (parent->_right == cur)
						{
							RotateL(grandparent);
							grandparent->_col = RED;
							parent->_col = BLACK;
						}
						else
						{
						/*    g
						   u     p
							   c    */
				        //右单旋+左单旋+变色
							RotateR(parent);
							RotateL(grandparent);
							cur->_col = BLACK;
							grandparent->_col = RED;
						}
						break;
					}
				}
					
				else
				{
					Node* uncle = grandparent->_right;
					//情况1:u存在且为红,变色加向上调整
					if (uncle && uncle->_col == RED)
					{
						parent->_col = BLACK;
						uncle->_col = BLACK;
						grandparent->_col = RED;

						//向上调整
						cur = grandparent;
						parent = cur->_parent;
					}
					else//情况2b:u不存在或者u存在且为黑  旋转+变色
					{
						/*    g
						   p     u 
						c              */
						//右单旋+变色
						if (parent->_right == cur)
						{
							RotateR(grandparent);
							grandparent->_col = RED;
							parent->_col = BLACK;
						}
						else
						{
						/*    g
						   p     u
							  c        */
						//左单旋+右单旋+变色
							RotateL(parent);
							RotateR(grandparent);
							cur->_col = BLACK;
							grandparent->_col = RED;
						}
						break;
					}
					
				}
		}
		_root->_col = BLACK;//管你变成什么色,根反正最后还是黑色
		return true;

 4.红黑树的验证

验证是红黑树,就要满足他的性质,首先不能出现连续红色节点,其次每条路径的黑色节点的数量要相等

不能出现连续红色节点:不要用cur,然后和cur->孩子来比较,因为会有两个孩子,比较麻烦,可以用cur->parent来比较

每条路径的黑色节点的数量要相等:先算出一条路径的黑色节点的数量,作为基准值,进行比较

bool IsRBTree()
		{
			if (_root && _root->_col == RED)
			{
				cout << "根节点颜色是红色" << endl;
				return false;
			}
			int nummark = 0;//给个黑色节点基准值,然后和它比较
			Node* cur = _root;
			while (cur)
			{
				if(cur->_col == BLACK)
					nummark++;

				cur=cur->_left;
			}
			return _Check(_root, 0, nummark);
		}
bool _Check(Node* root, int blacknum, int nummark)
	{
		if (root == nullptr)
		{
			if (nummark != blacknum)
			{
				cout << "某条路径黑色节点的数量不相等" << endl;
				cout << blacknum << endl;
				return false;
			}

			return true;
		}
		if (root->_col == BLACK)
		{
			blacknum++;
		}

		if (root->_col == RED && root->_parent && root->_parent->_col == RED)
		{
			cout << "具有连续的红色节点" << endl;
			return false;
		}

		return _Check(root->_left, blacknum, nummark)
			&& _Check(root->_right, blacknum, nummark);
	}
void testRBTree()
{
	srand(time(0));
	const size_t N = 5000000;
	RBTree<int, int> t;
	for (size_t i = 0; i < N; ++i)
	{
		size_t x = rand() + i;
		t.Insert(make_pair(x, x));
	}

	//t.Inorder();

	cout << t.IsRBTree() << endl;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奇点 ♡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值