关于红黑树---详解版

120 阅读8分钟

关于红黑树的概念


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

image.png

满足以上红黑树的性质,就能保证该棵树是一颗平衡树吗?为什么?

我们在概念中提到,红黑树确保没有一条路径会比其他路径长2倍,因而是接近平衡的。因此问题就转变为为什么如果这颗树是一颗红黑树,就能保证其最长路径中节点个数不会超过最短路径节点个数的两倍?

  • 根据第三点,红色节点的孩子是黑色的,这点能保证没有连续的两个红色节点。
  • 根据第四点,从该节点到后代的叶子路径上,包含数量相同的黑色节点,此处假如是从根节点计算,最坏情况下根节点左孩子为空,此时说明了从根节点开始一条路径上只有2个黑色节点(不包含NULL节点),这也要求了根节点的右孩子必须且有2个黑色节点,此时根节点的右孩子可以存在一个红色节点,但是配合第三点,如果存在红色节点且红色节点的孩子一定是黑色的,此时右子树中任意一条路径的黑色节点已经达到两个,说明不能再存在黑色节点了,因此在黑色几点下最后链接一个红色节点右子树就需要停止。(如下图所示为例)

image.png

此时我们发现最短的路径长度为2(15->9),最长的路径长度为4(15->19->17->16)【其一】,这也就验证了一颗红黑树中,其最长路径中的节点个数不会超过最短路径中的节点个数的两倍!


红黑树节点的定义&代码

enum Colour
{
	RED,
	BLACK,
};

template<class K, class V>
struct RBTreeNode
{
	//节点以及数据
	RBTreeNode<K, V>* _left;
	RBTreeNode<K, V>* _right;
	RBTreeNode<K, V>* _parent;
	pair<K, V> _kv;

	Colour _col;

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

在上述红黑树节点的定义中,新节点的_col默认给成红色是有意为之还是红黑色都可以呢?

当我们插入一个节点之后,可能会破坏红黑树的规则,因此我们插入一个节点要尽可能的少破坏红黑树的规则。而插入红色节点,是可能会破坏性质3,因为可能会导致连续的红色节点;而插入黑色节点,是会一定破坏性质4,因为插入一个黑色节点必然会使插入节点的这一条路径黑色节点个数增加1,从而导致性质4被破坏,因此从破坏力度来说选择红色节点,插入红色节点可能破坏性质3,插入黑色节点一定破坏性质4。

从维护红黑树的角度来说,也是破坏4更难维护,因为它牵扯到每一条路径,可能会让红黑树产生翻天覆地的变化(具体详情往下看Insert)。


红黑树的插入&代码:


红黑树是在二叉搜索树的基础上加上其平衡限制条件,因此红黑树的插入可以分为两步:

1.按照二叉搜索树的规则插入新节点

2.检测新节点插入后,红黑树的性质是否被破坏。

  1. 如果双亲节点的颜色是黑色,那说明没有违反红黑树的任何性质,则不需要调整。
  2. 当新插入节点的双亲节点颜色红色时,此时违反性质三(不能有连续的红色节点),此时需要对红黑树进行调整。调整需分情况来讨论:(约定cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点)

情况一:cur为红,p为红,g为黑,u存在且为红

注意:此处看到的树,可能是一颗完整的树,也可能是一颗子树。

image.png 如果g是根节点,调整完成后,需要将g改为黑色

如果g是子树,g一定有双亲,且g的双亲如果是红色,需要继续向上调整

image.png cur和p均为红,违反了性质3。解决方式:将p,u改为黑,g改为红,然后把g当成cur,继续向上调整。


情况二:cur为红,p为红,g为黑,u不存在/u存在且为黑

image.png

说明:u的情况有两种:

  • 如果u节点不存在,则cur一定是新插入节点,因为如果cur不是新插入节点,则cur和p一定有一个节点的颜色是黑色,就不满足性质4:每条路径黑色节点个数相同
  • 如果u节点存在,则其一定为黑色的,那么cur节点原来的颜色一定是黑色的,现在看到其是红色的原因是因为cur的子树在调整的过程中将cur节点的颜色由黑色改成红色

p为g的左孩子,cur为p的左孩子则进行右单旋;

p为g的右孩子,cur为p的右孩子,则进行左单旋;

p,g变色--p变成黑,g变成红。(旋转规则在AVL树中有详细讲解,大家可参考上篇博文(AVL树详解,以及四种旋转的图解 - 掘金 (juejin.cn))


情况三:cur为红,p为红,g为黑,u不存在/u存在且为黑

image.png

p为g的左孩子,cur为p的右孩子,则针对p做左单旋;

p为g的右孩子,cur为p的左孩子,则针对p做右单旋;

则转换为了情况二。


bool Insert(const pair<K, V>& kv)
	{
		if (_root == nullptr)
		{
			_root = new Node(kv);
			_root->_col = BLACK;
			return true;
		}

		Node* parent = nullptr;
		Node* cur = _root;

		while (cur)
		{
			if (cur->_kv.first < kv.first)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_kv.first > kv.first)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				return false;
			}
		}
		cur = new Node(kv);
		cur->_col = RED;
		if (kv.first < parent->_kv.first)
		{
			parent->_left = cur;
		}
		else
		{
			parent->_right = cur;
		}
		cur->_parent = parent;


		while (parent && parent->_col == RED)
		{
			Node* grandfather = parent->_parent;
			assert(grandfather);

			if (parent == grandfather->_left)//父亲为祖父的左孩子
			{
				Node* uncle = grandfather->_right;
				if (uncle != nullptr && uncle->_col == RED)//叔叔存在且为红
				{
					//更新节点的颜色
					parent->_col = BLACK;
					uncle->_col = BLACK;

					grandfather->_col = RED;

					//继续向上更新
					cur = grandfather;
					parent = cur->_parent;
				}
				else//叔叔不存在或者叔叔存在且为黑 这个时候就要旋转了
				{
					if (cur == parent->_left)
					{
						//右单旋
						RotateR(grandfather);
						//更新节点颜色
						grandfather->_col = RED;
						parent->_col = BLACK;

					}
					else
					{
						//双旋,先左再右
						RotateL(parent);
						RotateR(grandfather);
						//更新节点颜色
						grandfather->_col = RED;
						cur->_col = BLACK;
					}

					break;

				}
			}
			else//父亲为祖父的右孩子
			{
				Node* uncle = grandfather->_left;
				if (uncle != nullptr && uncle->_col == RED)//叔叔存在且为红
				{
					//更新节点的颜色
					parent->_col = BLACK;
					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);

						//更新节点
						grandfather->_col = RED;
						cur->_col = BLACK;

					}

					break;

				}
			}
		}

		_root->_col = BLACK;
		return true;

	}

红黑树完整代码(带验证红黑树的代码)


#pragma once
#include<assert.h>
#include<vector>
#include<queue>
#include<iostream>
using namespace std;

enum Colour
{
	RED,
	BLACK,
};

template<class K, class V>
struct RBTreeNode
{
	//节点以及数据
	RBTreeNode<K, V>* _left;
	RBTreeNode<K, V>* _right;
	RBTreeNode<K, V>* _parent;
	pair<K, V> _kv;

	Colour _col;

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

template<class K, class V>
class RBTree
{
	typedef RBTreeNode<K, V> Node;
public:
	bool Insert(const pair<K, V>& kv)
	{
		if (_root == nullptr)
		{
			_root = new Node(kv);
			_root->_col = BLACK;
			return true;
		}

		Node* parent = nullptr;
		Node* cur = _root;

		while (cur)
		{
			if (cur->_kv.first < kv.first)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_kv.first > kv.first)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				return false;
			}
		}
		cur = new Node(kv);
		cur->_col = RED;
		if (kv.first < parent->_kv.first)
		{
			parent->_left = cur;
		}
		else
		{
			parent->_right = cur;
		}
		cur->_parent = parent;


		while (parent && parent->_col == RED)
		{
			Node* grandfather = parent->_parent;
			assert(grandfather);

			if (parent == grandfather->_left)//父亲为祖父的左孩子
			{
				Node* uncle = grandfather->_right;
				if (uncle != nullptr && uncle->_col == RED)//叔叔存在且为红
				{
					//更新节点的颜色
					parent->_col = BLACK;
					uncle->_col = BLACK;

					grandfather->_col = RED;

					//继续向上更新
					cur = grandfather;
					parent = cur->_parent;
				}
				else//叔叔不存在或者叔叔存在且为黑 这个时候就要旋转了
				{
					if (cur == parent->_left)
					{
						//右单旋
						RotateR(grandfather);
						//更新节点颜色
						grandfather->_col = RED;
						parent->_col = BLACK;

					}
					else
					{
						//双旋,先左再右
						RotateL(parent);
						RotateR(grandfather);
						//更新节点颜色
						grandfather->_col = RED;
						cur->_col = BLACK;
					}

					break;

				}
			}
			else//父亲为祖父的右孩子
			{
				Node* uncle = grandfather->_left;
				if (uncle != nullptr && uncle->_col == RED)//叔叔存在且为红
				{
					//更新节点的颜色
					parent->_col = BLACK;
					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);

						//更新节点
						grandfather->_col = RED;
						cur->_col = BLACK;

					}

					break;

				}
			}
		}

		_root->_col = BLACK;
		return true;

	}
public:
	void RotateL(Node* parent)
	{
		Node* SubR = parent->_right;
		Node* SubRL = SubR->_left;

		parent->_right = SubRL;
		if (SubRL != nullptr)
			SubRL->_parent = parent;

		if (parent == _root)
		{
			_root = SubR;
			_root->_parent = nullptr;
		}
		else
		{
			Node* ppNode = parent->_parent;
			if (parent == ppNode->_left)
			{
				ppNode->_left = SubR;
			}
			else
			{
				ppNode->_right = SubR;
			}
			SubR->_parent = ppNode;

		}
		SubR->_left = parent;
		parent->_parent = SubR;
	}
	void RotateR(Node* parent)
	{
		Node* SubL = parent->_left;
		Node* SubLR = SubL->_right;

		parent->_left = SubLR;
		if (SubLR != nullptr)
			SubLR->_parent = parent;

		if (parent == _root)
		{
			_root = SubL;
			_root->_parent = nullptr;
		}
		else
		{
			Node* ppNode = parent->_parent;

			if (ppNode->_left == parent)
			{
				ppNode->_left = SubL;
			}
			else
			{
				ppNode->_right = SubL;
			}

			SubL->_parent = ppNode;
		}

		SubL->_right = parent;
		parent->_parent = SubL;

	}

	vector<vector<int>> levelOrder() {
		vector<vector<int>> vv;
		if (_root == nullptr)
			return vv;

		queue<Node*> q;
		int levelSize = 1;
		q.push(_root);

		while (!q.empty())
		{
			// levelSize控制一层一层出
			vector<int> levelV;
			while (levelSize--)
			{
				Node* front = q.front();
				q.pop();
				levelV.push_back(front->_kv.first);
				if (front->_left)
					q.push(front->_left);

				if (front->_right)
					q.push(front->_right);
			}
			vv.push_back(levelV);
			for (auto e : levelV)
			{
				cout << e << " ";
			}
			cout << endl;

			// 上一层出完,下一层就都进队列
			levelSize = q.size();
		}

		return vv;
	}
	int _maxHeight(Node* root)
	{
		if (root == nullptr)
			return 0;

		int lh = _maxHeight(root->_left);
		int rh = _maxHeight(root->_right);

		return lh > rh ? lh + 1 : rh + 1;
	}

	int _minHeight(Node* root)
	{
		if (root == nullptr)
			return 0;

		int lh = _minHeight(root->_left);
		int rh = _minHeight(root->_right);

		return lh < rh ? lh + 1 : rh + 1;
	}


	void _InOrder(Node* root)
	{
		if (root == nullptr)
			return;

		_InOrder(root->_left);
		cout << root->_kv.first << " ";
		_InOrder(root->_right);
	}

	bool _IsValidRBTree(Node* pRoot, size_t k, const size_t blackCount)
	{
		//走到null之后,判断k和black是否相等
		if (nullptr == pRoot)
		{
			if (k != blackCount)
			{
				cout << "违反性质四:每条路径中黑色节点的个数必须相同" << endl;
				return false;
			}
			return true;
		}

		// 统计黑色节点的个数
		if (BLACK == pRoot->_col)
			k++;

		// 检测当前节点与其双亲是否都为红色
		if (RED == pRoot->_col && pRoot->_parent && pRoot->_parent->_col == RED)
		{
			cout << "违反性质三:存在连在一起的红色节点" << endl;
			return false;
		}

		return _IsValidRBTree(pRoot->_left, k, blackCount) &&
			_IsValidRBTree(pRoot->_right, k, blackCount);
	}

public:
	Node* LeftMost()
	{
		return  _LeftMost(_root);
	}
	Node* RightMost()
	{
		return _RightMost(_root);
	}

	void InOrder()
	{
		_InOrder(_root);
		cout << endl;
	}

	void Height()
	{
		cout << "最长路径:" << _maxHeight(_root) << endl;
		cout << "最短路径:" << _minHeight(_root) << endl;
	}


	bool IsBalanceTree()
	{
		// 检查红黑树几条规则

		Node* pRoot = _root;
		// 空树也是红黑树
		if (nullptr == pRoot)
			return true;

		// 检测根节点是否满足情况
		if (BLACK != pRoot->_col)
		{
			cout << "违反红黑树性质二:根节点必须为黑色" << endl;
			return false;
		}

		// 获取任意一条路径中黑色节点的个数 -- 比较基准值
		size_t blackCount = 0;
		Node* pCur = pRoot;
		while (pCur)
		{
			if (BLACK == pCur->_col)
				blackCount++;

			pCur = pCur->_left;
		}

		// 检测是否满足红黑树的性质,k用来记录路径中黑色节点的个数
		size_t k = 0;
		return _IsValidRBTree(pRoot, k, blackCount);
	}

private:
	Node* _LeftMost(Node* root)
	{
		if (root->_left == nullptr)
			return root;
		return _LeftMost(root->_left);
	}
	Node* _RightMost(Node* root)
	{
		if (root->_right == nullptr)
			return root;
		return _RightMost(root->_right);
	}
	

private:
	Node* _root = nullptr;
};

void TestRBTree1()
{
	//int a[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
	int a[] = { 30, 29, 28, 27, 26, 25, 24, 11, 8, 7, 6, 5, 4, 3, 2, 1 };
	RBTree<int, int> t;
	for (auto e : a)
	{
		t.Insert(make_pair(e, e));
	}
	t.levelOrder();
	t.InOrder();
	t.Height();
	cout << t.LeftMost()->_kv.first << endl;
	cout << t.RightMost()->_kv.first << endl;
}

void TestRBTree2()
{
	const size_t N = 1024 * 1024;
	vector<int> v;
	v.reserve(N);
	srand(time(0));
	for (size_t i = 0; i < N; ++i)
	{
		v.push_back(rand());
		//v.push_back(i);
	}

	RBTree<int, int> t;
	for (auto e : v)
	{
		t.Insert(make_pair(e, e));
	}

	//t.levelOrder();
	//cout << endl;
	cout << "是否平衡?" << t.IsBalanceTree() << endl;
	t.Height();

	//t.InOrder();

}
#include<iostream>
#include"RBTree.h"

using namespace std;
int main()
{
	TestRBTree1();
	TestRBTree2();
	return 0;
}