【C++】红黑树

红黑树的概念和性质

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

性质:

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

红黑树结点定义

cpp 复制代码
enum Colour
{
	RED,
	BLACK,
};

template<class K, class V>
struct RBTreeNode
{
public:
	RBTreeNode<K, V>* _left;
	RBTreeNode<K, V>* _right;
	RBTreeNode<K, V>* _parent;

	pair<K, V> _kv;
	Colour _col;

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

红黑树结点插入

情况一:

cur为红,p为红,g为黑,u存在且为红

cpp 复制代码
//如果父亲不为空和结点颜色为红色就执行这个循环
		while (parent && parent->_col == RED)
		{
			//父亲结点位于左边
			Node* grandfather = parent->_parent;
			if (grandfather->_left == parent)
			{
				Node* uncle = grandfather->_right;
				//情况一:uncle存在且为红色,且parent也为红色
				//		g
				//	 p	   u
				//c
				if (uncle && uncle->_col == RED)
				{
					parent->_col = BLACK;
					uncle->_col = BLACK;
					grandfather->_col = RED;

					//继续往上调整
					cur = grandfather;
					parent = cur->_parent;
				}

情况二:

cur为红,p为红,g为黑,u不存在/u存在且为黑,需要进行旋转
旋转条件:

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

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

uncle不存在

uncle存在且为黑色

情况三:

cur为红,p为红,g为黑,u不存在/u存在且为黑

旋转条件采用情况二的方法。
uncle不存在

uncle存在

cpp 复制代码
//情况二和三:uncle不存在或者uncle为黑色则进行旋转变色,并继续向上处理
				else
				{
					//		g
					//	 p	   u
					//c
					if (cur == parent->_left)
					{
						RotateR(grandfather);
						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					else
					{
						//		g
						//	 p	   u
						//		c
						RotateL(parent);
						RotateR(grandfather);
						cur->_col = BLACK;
						parent->_col = RED;
						grandfather->_col = RED;
					}
					break;
				}
			}
			else
			{
				//父亲结点位于右边
				//		g
				//	 u	   p
				//				c
				Node* uncle = grandfather->_left;
				//情况一:uncle存在且为红色,且parent也为红色
				if (uncle && uncle->_col == RED)
				{
					parent->_col = BLACK;
					uncle->_col = BLACK;
					grandfather->_col = RED;

					//继续往上调整
					cur = grandfather;
					parent = cur->_parent;
				}
				//情况二和三:uncle不存在或者uncle为黑色则进行旋转变色,并继续向上处理
				else
				{
					//		g
					//	 u	   p
					//				c
					if (cur == parent->_right)
					{
						RotateL(grandfather);
						grandfather->_col = RED;
						parent->_col = BLACK;
					}
					else
					{
						//		g
						//	 u	   p
						//      c
						RotateR(parent);
						RotateL(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}
					break;
				}
			}
			
		}
		_root->_col = BLACK;

检测红黑树结点平衡

根据红黑树的性质,我们可以通过以下方式来进行判断。

根节点必须为黑色,不可以有相连的红色结点和每条路径上的黑色结点个数都相等。

cpp 复制代码
	bool IsBalance()
	{
		if (_root && _root->_col == RED)
		{
			cout << "根结点的颜色为红色" << endl;
			return false;
		}
		//计算黑色结点
		int benchmark = 0;
		Node* cur = _root;
		while (cur)
		{
			if (cur->_col == BLACK)
			{
				++benchmark;
			}
			cur = cur->_left;
		}

		//连续的红色结点
		_Check(_root,0,benchmark);
	}
	bool _Check(Node* root,int blackNum,int benchmark)
	{
		if (root == nullptr)
		{
			if (blackNum != benchmark)
			{
				cout << "有条路劲的黑色结点个数不一样" << 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,benchmark)
					&& _Check(root->_right,blackNum,benchmark);
	}

源码

cpp 复制代码
#pragma once
#include <iostream>
using namespace std;
enum Colour
{
	RED,
	BLACK,
};

template<class T>
struct RBTreeNode
{
public:
	RBTreeNode<T>* _left;
	RBTreeNode<T>* _right;
	RBTreeNode<T>* _parent;

	T _data;
	Colour _col;

	RBTreeNode(const T& data)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _data(data)
		, _col(RED)
	{}
};

template<class T,class Ref,class Ptr>
struct __RBTreeIterator
{
	typedef RBTreeNode<T> Node;
	typedef __RBTreeIterator<T, Ref, Ptr> Self;
	Node* _node;

	__RBTreeIterator(Node* node)
		:_node(node)
	{}

	__RBTreeIterator(const __RBTreeIterator<T,T&,T*>& it)
		:_node(it._node)
	{}

	Ref operator*()
	{
		return _node->_data;
	}

	Ptr operator->()
	{
		return &_node->_data;
	}
	bool operator!=(const Self& s)
	{
		return _node != s._node;
	}

	Self& operator++()
	{
		if (_node->_right)
		{
			// 1、右不为空,下一个就是右子树的最左节点
			Node* subLeft = _node->_right;
			while (subLeft->_left)
			{
				subLeft = subLeft->_left;
			}

			_node = subLeft;
		}
		else
		{
			// 2、右为空,沿着到根的路径,找孩子是父亲左的那个祖先
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && parent->_right == cur)
			{
				cur = parent;
				parent = cur->_parent;
			}
			_node = parent;
		}
		return *this;
	}

	Self& operator--()
	{
		if (_node->_left)
		{
			// 1、左不为空,找左子树最右节点
			Node* subLeft = _node->_left;
			while (subLeft->_right)
			{
				subLeft = subLeft->_right;
			}

			_node = subLeft;
		}
		else
		{
			// 2、左为空,孩子是父亲的右的那个祖先
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && parent->_left)
			{
				cur = parent;
				parent = cur->_parent;
			}
			_node = parent;
			
		}
		return *this;
	}

};

template<class K, class T,class KeyOft>
class RBTree
{
	typedef RBTreeNode<T> Node;
public:
	~RBTree()
	{
		_Destroy(_root);
		_root = nullptr;
	}

public:
	typedef __RBTreeIterator<T, T&, T*> iterator;
	typedef __RBTreeIterator<T, const T&, const T*> const_iterator;

	iterator begin()
	{
		Node* cur = _root;
		while (cur && cur->_left)
		{
			cur = cur->_left;
		}
		return iterator(cur);
	}

	iterator end()
	{
		return iterator(nullptr);
	}


	Node* Find(const K& key)
	{
		Node* cur = _root;
		KeyOft kot;
		while (cur)
		{
			if (kot(cur->_data) < key)
			{
				cur = cur->_right;
			}
			else if (kot(cur->_data) > key)
			{
				cur = cur->_left;
			}
			else
			{
				return cur;
			}
		}
		return nullptr;
	}

	pair<iterator,bool> Insert(const T& data)
	{
		KeyOft kot;
		if (_root == NULL)
		{
			_root = new Node(data);
			_root->_col = BLACK;
			//返回已经构建好的迭代器
			return make_pair(iterator(_root),true);
		}
		Node* cur = _root;
		Node* parent = nullptr;
		while (cur)
		{
			if (kot(cur->_data) < kot(data))
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (kot(cur->_data) > kot(data))
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				//插入失败,返回存在的迭代器
				return make_pair(iterator(cur), false);
			}
		}
		cur = new Node(data);

		//保存新结点用于放回,因为cur总是进行变色处理
		Node* newnode = cur;
		if (kot(parent->_data) < kot(data))
			//if(parent->_right == cur)
		{
			parent->_right = cur;
		}
		else
		{
			parent->_left = cur;
		}
		cur->_parent = parent;

		//如果父亲不为空和结点颜色为红色就执行这个循环
		while (parent && parent->_col == RED)
		{
			//父亲结点位于左边
			Node* grandfather = parent->_parent;
			if (grandfather->_left == parent)
			{
				Node* uncle = grandfather->_right;
				//情况一:uncle存在且为红色,且parent也为红色
				//		g
				//	 p	   u
				//c
				if (uncle && uncle->_col == RED)
				{
					parent->_col = BLACK;
					uncle->_col = BLACK;
					grandfather->_col = RED;

					//继续往上调整
					cur = grandfather;
					parent = cur->_parent;
				}
				//情况二和三:uncle不存在或者uncle为黑色则进行旋转变色,并继续向上处理
				else
				{
					//		g
					//	 p	   u
					//c
					if (cur == parent->_left)
					{
						RotateR(grandfather);
						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					else
					{
						//		g
						//	 p	   u
						//		c
						RotateL(parent);
						RotateR(grandfather);
						cur->_col = BLACK;
						parent->_col = RED;
						grandfather->_col = RED;
					}
					break;
				}
			}
			else
			{
				//父亲结点位于右边
				//		g
				//	 u	   p
				//				c
				Node* uncle = grandfather->_left;
				//情况一:uncle存在且为红色,且parent也为红色
				if (uncle && uncle->_col == RED)
				{
					parent->_col = BLACK;
					uncle->_col = BLACK;
					grandfather->_col = RED;

					//继续往上调整
					cur = grandfather;
					parent = cur->_parent;
				}
				//情况二和三:uncle不存在或者uncle为黑色则进行旋转变色,并继续向上处理
				else
				{
					//		g
					//	 u	   p
					//				c
					if (cur == parent->_right)
					{
						RotateL(grandfather);
						grandfather->_col = RED;
						parent->_col = BLACK;
					}
					else
					{
						//		g
						//	 u	   p
						//      c
						RotateR(parent);
						RotateL(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}
					break;
				}
			}
			
		}
		_root->_col = BLACK;
		return make_pair(iterator(newnode), true);
	}

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

	bool IsBalance()
	{
		if (_root && _root->_col == RED)
		{
			cout << "根结点的颜色为红色" << endl;
			return false;
		}
		//计算黑色结点
		int benchmark = 0;
		Node* cur = _root;
		while (cur)
		{
			if (cur->_col == BLACK)
			{
				++benchmark;
			}
			cur = cur->_left;
		}

		//连续的红色结点
		_Check(_root,0,benchmark);
	}

	int Height()
	{
		return _Height(_root);
	}

private:

	void _Destroy(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
		_Destroy(root->_left);
		_Destroy(root->_right);
		delete root;
	}

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

		int leftH = _Height(root->_left);
		int rightH = _Height(root->_right);

		return leftH > rightH ? leftH + 1 : rightH + 1;
	}

	bool _Check(Node* root,int blackNum,int benchmark)
	{
		if (root == nullptr)
		{
			if (blackNum != benchmark)
			{
				cout << "有条路劲的黑色结点个数不一样" << 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,benchmark)
					&& _Check(root->_right,blackNum,benchmark);
	}

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

		Node* ppNode = parent->_parent;
		subR->_left = parent;
		parent->_parent = subR;

		//1.parent是整棵树的根
		//2.parent是子树的根
		if (parent == _root)
		{
			_root = subR;
			subR->_parent = nullptr;
		}
		else
		{
			if (ppNode->_left == parent)
			{
				ppNode->_left = subR;
			}
			else
			{
				ppNode->_right = subR;
			}
			subR->_parent = ppNode;
		}
	}

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

		parent->_left = subLR;
		if (subLR)
		{
			subLR->_parent = parent;
		}

		Node* ppNode = parent->_parent;
		subL->_right = parent;
		parent->_parent = subL;

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


	}

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

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

	Node* _root = nullptr;
};

//void Test_RBTree1()
//{
//	//int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
//	int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
//	RBTree<int, int> t1;
//	for (auto e : a)
//	{
//		/*	if (e == 14)
//			{
//			int x = 0;
//			}*/
//
//		t1.Insert(make_pair(e, e));
//	}
//
//	t1.InOrder();
//	cout << t1.IsBalance() << endl;
//
//	cout << t1.Height() << endl;
//}
相关推荐
s_little_monster22 分钟前
【QT】QT入门
数据库·c++·经验分享·笔记·qt·学习·mfc
Yingye Zhu(HPXXZYY)29 分钟前
洛谷 P11045 [蓝桥杯 2024 省 Java B] 最优分组
c++·蓝桥杯
三玖诶39 分钟前
第一弹:C++ 的基本知识概述
开发语言·c++
木向2 小时前
leetcode42:接雨水
开发语言·c++·算法·leetcode
sukalot2 小时前
windows C++-创建基于代理的应用程序(下)
c++
labuladuo5202 小时前
AtCoder Beginner Contest 372 F题(dp)
c++·算法·动态规划
DieSnowK2 小时前
[C++][第三方库][httplib]详细讲解
服务器·开发语言·c++·http·第三方库·新手向·httplib
StrokeAce4 小时前
linux桌面软件(wps)内嵌到主窗口后的关闭问题
linux·c++·qt·wps·窗口内嵌
家有狸花7 小时前
VSCODE驯服日记(三):配置C++环境
c++·ide·vscode