【C++】红黑树

红黑树 

目录

a. 红黑树的概念

b. 红黑树的性质

c. 红黑树的实现


a. 红黑树的概念

红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或

Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路

径会比其他路径长出俩倍,因而是接近平衡的

b. 红黑树的性质

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

c. 红黑树的实现

(一)红黑树节点的构建

代码

	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)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _kv(kv)
		, _col(RED)  //默认为红节点,对于性质四,黑节点数不好控制,先默认红节点,后期再变颜色
	{}
};

(二)红黑树的插入

实现思路

如果插入的是第一个节点(即根节点),由于性质二,我们需要把它变成黑色

除了上述情况,还有一种可能需要变色(回到性质三)

如图:

而面对这种情况,也分不同的做法

对于第一种情况(左图):

做法是把 parent 变成黑色的 , grandparent 变成红色的 ,uncle 变成黑色的 ,

然后 cur = grandparent , parent = cur->_parent , grandparent = parent->_parent ,uncle 也有变节点 ,直到不满足两个红节点连在一起的前提 或者 是 parent 为空(循环结束的条件)

注意:

根节点的颜色可能会在过程中更改(如上述右图),一定要在最后改回成黑色

对于第二种情况:

parent 变成黑色 , grandparent 变成红色 ,再发生旋转(跟 AVL树 的旋转情况一样),完成 break即可

 

 代码

	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)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _kv(kv)
		, _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->_parent = parent;
		if (parent->_kv.first > cur->_kv.first)
		{
			parent->_left = cur;
		}
		else
		{
			parent->_right = cur;
		}
		while (parent && parent->_col == RED)
		{
			Node* grandparent = parent->_parent;
			if (parent == grandparent->_left)
			{
				Node* uncle = grandparent->_right;
				if (uncle && uncle->_col == RED)
				{
					parent->_col = BLACK;
					uncle->_col = BLACK;
					grandparent->_col = RED;

					cur = grandparent;
					parent = cur->_parent;
				}
				else
				{
					if (grandparent->_left == parent && parent->_left == cur)
					{
						RotateR(grandparent);
					}
					else
					{
						RotateLR(grandparent);
					}
					parent->_col = BLACK;
					grandparent->_col = RED;
					
					cur = grandparent;
					parent = cur->_parent;
				}
			}
			else
			{
				Node* uncle = grandparent->_left;
					if (uncle && uncle->_col == RED)
					{
						parent->_col = BLACK;
						uncle->_col = BLACK;
						grandparent->_col = RED;

						cur = grandparent;
						parent = cur->_parent;
					}
					else
					{
						
						if (grandparent->_right == parent && parent->_right == cur)
						{
							RotateL(grandparent);
						}
						else
						{
							RotateRL(grandparent);
						}
						parent->_col = BLACK;
						grandparent->_col = RED;
						
						cur = grandparent;
						parent = cur->_parent;
					}
			}
		}
		_root->_col = BLACK;
		return true;
	}
	void InOder()
	{
		_InOder(_root);
	}
	bool IsBalance()
	{

		return  _IsBalance(_root, 0);
	}
	~RBTree()
	{
		Destory(_root);
		_root = nullptr;
	}
private:
	bool _IsBalance(Node* root,int MaxBlack) //验证是否是红黑树
	{
		if (root == nullptr)
		{
			cout << MaxBlack + 1 << endl;
			return true;
		}
		Node* parent = root->_parent;
		if (_root->_col == RED)
		{
			return false;
		}
		if (root->_col == RED && parent && parent->_col == RED)
		{
			return false;
		}
		if (root->_col == BLACK)
		{
			++MaxBlack;
		}
		return _IsBalance(root->_left, MaxBlack) && _IsBalance(root->_right, MaxBlack);
	}
	void RotateR(Node* root)
	{
		Node* SubL = root->_left;
		Node* SubLR = SubL->_right;
		if (root == _root)
		{
			_root = SubL;
		}
		else
		{
			Node* parent = root->_parent;
			if (parent->_left == root)
			{
				parent->_left = SubL;
			}
			else
			{
				parent->_right = SubL;
			}
		}
		root->_left = SubLR;
		SubL->_right = root;
		SubL->_parent = root->_parent;
		root->_parent = SubL;
	}
	void RotateL(Node* root)
	{
		Node* SubR = root->_right;
		Node* SunRL = SubR->_left;
		if (root == _root)
		{
			_root = SubR;
		}
		else
		{
			Node* parent = root->_parent;
			if (parent->_left == root)
			{
				parent->_left = SubR;
			}
			else
			{
				parent->_right = SubR;
			}
		}
		root->_right = SunRL;
		SubR->_left = root;
		SubR->_parent = root->_parent;
		root->_parent = SubR;
	}
	void RotateLR(Node* root)
	{
		Node* SubL = root->_left;
		Node* SubLR = SubL->_right;
		RotateL(SubL);
		RotateR(root);
	}
	void RotateRL(Node* root)
	{
		Node* SubR = root->_right;
		Node* SubRL = SubR->_left;
		RotateR(SubR);
		RotateL(root);
	}
	void _InOder(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
		_InOder(root->_left);
		cout << root->_kv.first << " " << root->_col << endl;
		_InOder(root->_right);
	}
	void Destory(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
		Destory(root->_left);
		Destory(root->_right);
		delete root;
	}
	Node* _root = nullptr;
};

  • 74
    点赞
  • 70
    收藏
    觉得还不错? 一键收藏
  • 59
    评论
抱歉,我是一名语言模型AI,无法为您提供演示实时代码功能。但是,我可以向您解释的基本原理和操作。是一种自平衡二叉搜索,它的每个节点都有一个颜色属性,色或色,具有以下特性: 1. 根节点为色。 2. 所有叶子节点(NIL节点)为色。 3. 如果一个节点为色,则它的两个子节点必须都为色。 4. 从任意一个节点到其每个叶子节点的所有路径都包含相同数量的色节点。 的基本操作包括插入、删除和查找。插入和删除操作会破坏的平衡性,需要通过旋转和重新着色来修复平衡。查找操作与二叉搜索相同,具有O(log n)的时间复杂度。 以下是的插入操作的伪代码: 1. 新节点插入到中,颜色为色。 2. 如果新节点的父节点为色,则不需要做任何操作,仍然平衡。 3. 如果新节点的父节点为色,需要进行以下操作: (1) 如果新节点的叔节点(父节点的兄弟节点)为色,则将父节点和叔节点涂,祖父节点涂,然后将当前节点指向祖父节点,重复步骤2。 (2) 如果新节点的叔节点为色,并且新节点是父节点的右子节点(父节点为祖父节点的左子节点),则将父节点左旋转,将当前节点指向父节点,重复步骤4。 (3) 如果新节点的叔节点为色,并且新节点是父节点的左子节点(父节点为祖父节点的右子节点),则将父节点右旋转,将当前节点指向父节点,重复步骤4。 4. 将父节点涂,祖父节点涂,然后进行以下操作: (1) 如果当前节点是父节点的左子节点,将祖父节点右旋转。 (2) 如果当前节点是父节点的右子节点,将祖父节点左旋转。 以上是的基本操作,希望能够帮助您理解的原理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 59
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值