【C++ RB树】

文章目录

红黑树

AVL树是一颗绝对平衡的二叉搜索树,要求每个节点的左右高度差的绝对值不超过1,这样保证查询时的高效时间复杂度O( l o g 2 N ) log_2 N) log2N),但是要维护其绝对平衡,旋转的次数比较多。因此,如果一颗树的结构经常修改,那么AVL树就不太合适,所以就有了红黑树。

红黑树的概念

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

红黑树的性质

  1. 每个节点不是红色就是黑色
  2. 根节点是黑色的
  3. 不存在连续的红色节点
  4. 任意一条从根到叶子的路径上的黑色节点的数量相同
    根据上面的性质,红黑树就可以确保没有一条路径会比其他路径长出两倍,因为每条路径上的黑色节点的数量相同,所以理论上最短边一定都是黑色节点,最长边一定是一黑一红的不断重复的路径。

红黑树节点的定义

cpp 复制代码
	enum Color
	{
		RED,
		BLACK
	};
	template<class K, class V>
	struct RBTreeNode
	{
		RBTreeNode<K, V>* _left;
		RBTreeNode<K, V>* _right;
		RBTreeNode<K, V>* _parent;
		Color _col;
		pair<K, V> _kv;
		RBTreeNode(const pair<K, V>& kv)
			:_left(nullptr)
			,_right(nullptr)
			,_parent(nullptr)
			,_col(RED)
			,_kv(kv)
		{}
	};

插入新节点的颜色一定是红色,因为如果新节点的颜色是黑色,那么每条路径上的黑色节点的数量就不相同了,处理起来就比较麻烦,所以宁愿出现连续的红色节点,也不能让某一条路径上多出一个黑色节点。

红黑树的插入

1.根据二叉搜索树的规则插入新节点

cpp 复制代码
bool Insert(const pair<K, V>& kv)
{
	if (_root == nullptr)
	{
		_root = new Node(kv);
		_root->_col = BLACK;
		return true;
	}
	Node* curr = _root;
	Node* parent = nullptr;
	while (curr)
	{
		if (curr->_kv.first < kv.first)
		{
			parent = curr;
			curr = curr->_right;
		}
		else if (curr->_kv.first > kv.first)
		{
			parent = curr;
			curr = curr->_left;
		}
		else
		{
			return false;
		}
	}
	curr = new Node(kv);
	if (parent->_kv.first < kv.first)
		parent->_right = curr;
	else
		parent->_left = curr;
	curr->_parent = parent;
........

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

cpp 复制代码
bool Insert(const pair<K, V>& kv)
{
	if (_root == nullptr)
	{
		_root = new Node(kv);
		_root->_col = BLACK;
		return true;
	}
	Node* curr = _root;
	Node* parent = nullptr;
	while (curr)
	{
		if (curr->_kv.first < kv.first)
		{
			parent = curr;
			curr = curr->_right;
		}
		else if (curr->_kv.first > kv.first)
		{
			parent = curr;
			curr = curr->_left;
		}
		else
		{
			return false;
		}
	}
	curr = new Node(kv);
	if (parent->_kv.first < kv.first)
		parent->_right = curr;
	else
		parent->_left = curr;
	curr->_parent = parent;

	while (parent && parent->_col == RED)
	{
		Node* grandfather = parent->_parent;
		if (parent == grandfather->_left)
		{
			Node* uncle = grandfather->_right;
			if (uncle && uncle->_col == RED)
			{
				parent->_col = uncle->_col = BLACK;
				grandfather->_col = RED;

				curr = grandfather;
				parent = curr->_parent;
			}
			else
			{
				if (curr == parent->_left)
				{
					//      g
					//   p     u
					//c
					RotatoR(grandfather);
					parent->_col = BLACK;
					grandfather->_col = RED;
				}
				else
				{
					//      g
					//   p     u
					//    c
					RotatoL(parent);
					RotatoR(grandfather);
					curr->_col = BLACK;
					grandfather->_col = RED;
				}
				break;
			}
		}
		else
		{
			Node* uncle = grandfather->_left;
			if (uncle && uncle->_col == RED)
			{
				parent->_col = uncle->_col = BLACK;
				grandfather->_col = RED;

				curr = grandfather;
				parent = curr->_parent;
			}
			else
			{
				if (curr == parent->_right)
				{
					//      g   
					//   u     p
					//           c
					RotatoL(grandfather);
					parent->_col = BLACK;
					grandfather->_col = RED;
				}
				else
				{
					//      g   
					//   u     p
					//        c
					RotatoR(parent);
					RotatoL(grandfather);
					curr->_col = BLACK;
					grandfather->_col = RED;
				}
				break;
			}
		}
		
	}
	_root->_col = BLACK;
	return true;
}
void RotatoL(Node* parent)
{
	Node* subR = parent->_right;
	Node* subRL = subR->_left;
	parent->_right = subRL;
	if (subRL)
		subRL->_parent = parent;
	subR->_left = parent;
	Node* ppnode = parent->_parent;
	parent->_parent = subR;
	if (parent == _root)
	{
		_root = subR;
		subR->_parent = nullptr;
	}
	else
	{
		if (ppnode->_left == parent)
			ppnode->_left = subR;
		else
			ppnode->_right = subR;
		subR->_parent = ppnode;
	}
}
void RotatoR(Node* parent)
{
	Node* subL = parent->_left;
	Node* subLR = subL->_right;
	parent->_left = subLR;
	if (subLR)
		subLR->_parent = parent;
	subL->_right = parent;
	Node* ppnode = parent->_parent;
	parent->_parent = subL;
	if (parent == _root)
	{
		_root = subL;
		subL->_parent = nullptr;
	}
	else
	{
		if (ppnode->_left == parent)
			ppnode->_left = subL;
		else
			ppnode->_right = subL;
		subL->_parent = ppnode;
	}
}

代码实现

cpp 复制代码
#pragma once
#include <utility>

namespace lw
{
	enum Color
	{
		RED,
		BLACK
	};
	template<class K, class V>
	struct RBTreeNode
	{
		RBTreeNode<K, V>* _left;
		RBTreeNode<K, V>* _right;
		RBTreeNode<K, V>* _parent;
		Color _col;
		pair<K, V> _kv;
		RBTreeNode(const pair<K, V>& kv)
			:_left(nullptr)
			,_right(nullptr)
			,_parent(nullptr)
			,_col(RED)
			,_kv(kv)
		{}
	};
	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* curr = _root;
			Node* parent = nullptr;
			while (curr)
			{
				if (curr->_kv.first < kv.first)
				{
					parent = curr;
					curr = curr->_right;
				}
				else if (curr->_kv.first > kv.first)
				{
					parent = curr;
					curr = curr->_left;
				}
				else
				{
					return false;
				}
			}
			curr = new Node(kv);
			if (parent->_kv.first < kv.first)
				parent->_right = curr;
			else
				parent->_left = curr;
			curr->_parent = parent;

			while (parent && parent->_col == RED)
			{
				Node* grandfather = parent->_parent;
				if (parent == grandfather->_left)
				{
					Node* uncle = grandfather->_right;
					if (uncle && uncle->_col == RED)
					{
						parent->_col = uncle->_col = BLACK;
						grandfather->_col = RED;

						curr = grandfather;
						parent = curr->_parent;
					}
					else
					{
						if (curr == parent->_left)
						{
							//      g
							//   p     u
							//c
							RotatoR(grandfather);
							parent->_col = BLACK;
							grandfather->_col = RED;
						}
						else
						{
							//      g
							//   p     u
							//    c
							RotatoL(parent);
							RotatoR(grandfather);
							curr->_col = BLACK;
							grandfather->_col = RED;
						}
						break;
					}
				}
				else
				{
					Node* uncle = grandfather->_left;
					if (uncle && uncle->_col == RED)
					{
						parent->_col = uncle->_col = BLACK;
						grandfather->_col = RED;

						curr = grandfather;
						parent = curr->_parent;
					}
					else
					{
						if (curr == parent->_right)
						{
							//      g   
							//   u     p
							//           c
							RotatoL(grandfather);
							parent->_col = BLACK;
							grandfather->_col = RED;
						}
						else
						{
							//      g   
							//   u     p
							//        c
							RotatoR(parent);
							RotatoL(grandfather);
							curr->_col = BLACK;
							grandfather->_col = RED;
						}
						break;
					}
				}
				
			}
			_root->_col = BLACK;
			return true;
		}
		void RotatoL(Node* parent)
		{
			Node* subR = parent->_right;
			Node* subRL = subR->_left;
			parent->_right = subRL;
			if (subRL)
				subRL->_parent = parent;
			subR->_left = parent;
			Node* ppnode = parent->_parent;
			parent->_parent = subR;
			if (parent == _root)
			{
				_root = subR;
				subR->_parent = nullptr;
			}
			else
			{
				if (ppnode->_left == parent)
					ppnode->_left = subR;
				else
					ppnode->_right = subR;
				subR->_parent = ppnode;
			}
		}
		void RotatoR(Node* parent)
		{
			Node* subL = parent->_left;
			Node* subLR = subL->_right;
			parent->_left = subLR;
			if (subLR)
				subLR->_parent = parent;
			subL->_right = parent;
			Node* ppnode = parent->_parent;
			parent->_parent = subL;
			if (parent == _root)
			{
				_root = subL;
				subL->_parent = nullptr;
			}
			else
			{
				if (ppnode->_left == parent)
					ppnode->_left = subL;
				else
					ppnode->_right = subL;
				subL->_parent = ppnode;
			}
		}
		void InOrder()
		{
			_InOrder(_root);
		}
		bool IsBalance()
		{
			if (_root && _root->_col == RED)
				return false;
			Node* left = _root;
			int count = 0;
			while (left)
			{
				if (left->_col == BLACK)
					count++;
				left = left->_left;
			}
			return check(_root, 0, count);
		}
	private:
		bool check(Node* root, int count, int refBlackNumber)
		{
			if (root == nullptr)
			{
				if (count == refBlackNumber)
					return true;
				else
					return false;
			}
			if (root->_col == RED && root->_parent->_col == RED)
				return false;
			if (root->_col == BLACK)
				count++;
			return check(root->_left, count, refBlackNumber)
				&& check(root->_right, count, refBlackNumber);
		}
		void _InOrder(Node* root)
		{
			if (root == nullptr)
				return;
			_InOrder(root->_left);
			cout << root->_kv.first << " : " << root->_kv.second << endl;
			_InOrder(root->_right);
		}
		Node* _root = nullptr;
	};
}

总结

红黑树和AVL树都是高效的平衡二叉树,增删改查的时间复杂度都是O( l o g 2 N log_2 N log2N),红黑树不追求绝对平衡,其只需保证最长路径不超过最短路径的2倍,相对而言,降低了插入和旋转的次数,所以在经常进行增删的结构中性能比AVL树更优,而且红黑树实现比较简单,所以实际运用中红黑树更多。

相关推荐
木向1 小时前
leetcode42:接雨水
开发语言·c++·算法·leetcode
sukalot1 小时前
windows C++-创建基于代理的应用程序(下)
c++
labuladuo5201 小时前
AtCoder Beginner Contest 372 F题(dp)
c++·算法·动态规划
DieSnowK1 小时前
[C++][第三方库][httplib]详细讲解
服务器·开发语言·c++·http·第三方库·新手向·httplib
StrokeAce3 小时前
linux桌面软件(wps)内嵌到主窗口后的关闭问题
linux·c++·qt·wps·窗口内嵌
家有狸花6 小时前
VSCODE驯服日记(三):配置C++环境
c++·ide·vscode
dengqingrui1237 小时前
【树形DP】AT_dp_p Independent Set 题解
c++·学习·算法·深度优先·图论·dp
C++忠实粉丝7 小时前
前缀和(8)_矩阵区域和
数据结构·c++·线性代数·算法·矩阵
ZZZ_O^O7 小时前
二分查找算法——寻找旋转排序数组中的最小值&点名
数据结构·c++·学习·算法·二叉树