【C++杂货铺】红黑树


目录

🌈前言🌈 

📁 红黑树的概念

📁 红黑树的性质

📁 红黑树节点的定义

📁 红黑树的插入操作

📁 红黑树和AVL树的比较

📁 全代码展示

📁 总结


🌈前言🌈 

        欢迎大家观看本期【C++杂货铺】,本期内容将讲解二叉搜索树的进阶——红黑树。红黑树是一种二叉搜索树,通过控制每个节点的颜色,来调整整棵树的高度。

        红黑树是set和map实现的底层实现,在下一期内容,我们将讲解STL中set和map的模拟实现。如果你对二叉搜索树还不是很了解,可以快速阅览下面这篇文章;

【C++杂货铺】二叉搜索树-CSDN博客

📁 红黑树的概念

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

📁 红黑树的性质

1. 每个节点不是红色就是黑色;

2. 根节点是黑色的;

3. 如果一个节点是红色的,那么它的两个孩子节点是黑色的;

4. 对于每个节点,从该节点到其他所有后代叶节点的简单路径上,均包含相同数目的黑色节点个数;

5. 每个叶子结点都是黑色的(此后的叶子结点指的是空节点)

📁 红黑树节点的定义

// 节点的颜色
enum Color{RED, BLACK};
// 红黑树节点的定义
template<class ValueType>
struct RBTreeNode
{
 RBTreeNode(const ValueType& data = ValueType(),Color color = RED)
     : _pLeft(nullptr), _pRight(nullptr), _pParent(nullptr)
     , _data(data), _color(color)
 {}
 RBTreeNode<ValueType>* _pLeft;   // 节点的左孩子
 RBTreeNode<ValueType>* _pRight;  // 节点的右孩子
 RBTreeNode<ValueType>* _pParent; // 节点的双亲(红黑树需要旋转,为了实现简单给
出该字段)
 ValueType _data;            // 节点的值域
 Color _color;               // 节点的颜色
};

📁 红黑树的插入操作

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

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

        新插入节点的默认颜色是红色。因为红色容易控制规则,如果默认插入黑色,需要保证从当前节点到叶子节点具有相同的黑色节点个数,不易控制。

        即先保证性质4不被违反,再来判断性质3是否被违反,如果违反就进行调整。

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

        如果双亲节点的颜色是黑色,没有违反规则,则不需要调整;当新插入节点的双亲节点颜色为红色时,就违反了性质3,即不能有连续在一起的红色节点,此时需要进行调整,可分为两种情况:

约定:cur为当前节点,p为父亲节点,g为祖父节点,u为叔叔节点

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

● 情况2:cur为红,p为红,g为黑,u存在且为黑 或者 u不存在

        当如子树如下图所示时,需要对红黑树进行双旋,先以p为根进行左旋,再以g为根进行右旋。下图是p在g的左子树的情况,考虑一下p在g的右子树,且cur为p的左子树的情况。

📁 红黑树和AVL树的比较

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

        map和set的底层就是红黑树。

📁 全代码展示

template <class T>
struct RBTreeNode
{
	typedef RBTreeNode<T> Node;

	RBTreeNode(const T& val = T())
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _val(val)
		, _color(RED)
	{}

	Node* _left;
	Node* _right;
	Node* _parent;
	T _val;
	Color _color;
};

template<class T>
class RBTree
{
	typedef RBTreeNode<T> Node;
public:
	bool Insert(const T& val)
	{
		if (_root == nullptr)
		{
			_root = new Node(val);
			_root->_color = Black;
			return true;
		}
		Node* cur = _root;
		Node* parent = nullptr;
		while (cur)
		{
			if (cur->_val > val)
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (cur->_val < val)
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				return false;
			}
		}

		cur = new Node(val);
		if (parent->_val < val)
		{
			parent->_right = cur;
		}
		else
		{
			parent->_left = cur;
		}
		cur->_parent = parent;

		//调整颜色,不能出现连续的红色
		while (parent && parent->_color == RED)
		{
			Node* grandfather = parent->_parent;
			if (parent == grandfather->_left)
			{
				//叔叔在右边
				//1. 叔叔存在,且为红色
				Node* uncle = grandfather->_right;
				if (uncle && uncle->_color == RED)
				{
					grandfather->_color = RED;
					uncle->_color = parent->_color = Black;
					cur = grandfather;
					parent = cur->_parent;
				}
				//2. 叔叔存在,且为黑色  ||  叔叔不存在
				else
				{
					/*
							g
						p		u
						c  
					*/
					if (cur == parent->_left)
					{
						RotateR(grandfather);
						parent->_color = Black;
						grandfather->_color = RED;
					}
					/*
							g
						p		u
						    c
					*/
					else
					{
						RotateL(parent);
						RotateR(grandfather);
						cur->_color = Black;
						grandfather->_color = RED;
					}
					break;
				}
			}
			else
			{
				//叔叔在左边
				//1. 叔叔存在,且为红色
				Node* uncle = grandfather->_left;
				if (uncle && uncle->_color == RED)
				{
					grandfather->_color = RED;
					parent->_color = uncle->_color = Black;
					cur = grandfather;
					parent = cur->_parent;
				}
				//2. 叔叔存在,且为黑色  ||  叔叔不存在
				else
				{
					/*
							g
						u		p
						            c
					*/
					if (cur == parent->_right)
					{
						RotateL(grandfather);
						parent->_color = Black;
						grandfather->_color = RED;
					}
					/*
							g
						u		p
							    c   
					*/
					else
					{
						RotateR(parent);
						RotateL(grandfather);
						cur->_color = Black;
						grandfather->_color = RED;
					}
					break;
				}
			}
		}

		_root->_color = Black;

		return true;
	}

//遍历
void InOrder()
{
	_InOrder(_root);
	cout << endl;
}
	
bool isBalance()
{
	if (_root == nullptr)
	{
		return true;
	}

	int BlackNum = 0;
	Node* cur = _root;
	while (cur)
	{
		if (cur->_color == Black)
			BlackNum++;
		cur = cur->_right;
	}

	return _isBalance(_root,0,BlackNum);
}

protected:
	bool _isBalance(Node* root,int count , const int& BlackNum)
	{
		if(root == nullptr)
		{
			if (count != BlackNum)
				return false;
			return true;
		}
		if (root->_color == RED && root->_parent->_color == RED)
		{
			cout << "red" << endl;
			return false;
		}
		if (root->_color == Black)
			count++;
		return _isBalance(root->_left,count,BlackNum)
			&& _isBalance(root->_right,count,BlackNum);
	}

	void _InOrder(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
			
		_InOrder(root->_left);
		cout << root->_val << endl;
		_InOrder(root->_right);
	}

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

		parent->_right = subRL;
		if (subRL)
			subRL->_parent = parent;

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

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

		}
	}

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

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

		subL->_right = parent;

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

		}
	}
private:
	Node* _root = nullptr;
};

📁 总结

        以上就是本期【C++杂货铺】的主要内容了,讲解了红黑树如果优化二叉搜索树,红黑树的概念,红黑树实现插入,以及红黑树的高度平衡调整,此外模拟实现了红黑树。

        如果感觉本期内容对你有帮助,欢迎点赞,收藏,关注Thanks♪(・ω・)ノ

  • 50
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 46
    评论
评论 46
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

秋刀鱼的滋味@

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

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

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

打赏作者

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

抵扣说明:

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

余额充值