C++之红黑树介绍及代码实现

本文详细介绍了红黑树的定义、性质以及插入过程中如何通过颜色调整保证平衡,包括节点定义、插入策略(uncle存在和不存在的情况)和代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一、红黑树介绍  

二、红黑树的实现

2.1 红黑树节点的定义

2.2 红黑树节点的插入 

2.2.1 uncle存在且为红

2.2.2 uncle不存在

2.3 总体代码实现


       

一、红黑树介绍  

    红黑树也是一种二叉搜索树,当然它也可以是空树,由名字我们就可以知道它的节点是有红黑两种颜色的,那么它是怎么来维持平衡的呢?红黑树通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的。

红黑树有以下五个性质:

  1. 每个节点不是黑色就是红色
  2. 根节点是黑色的
  3. 红色节点的两个孩子是黑色的
  4. 对于每个节点,从它到其所有后代叶子节点的简单路径上,均包含数量相同的黑色节点
  5. 每个叶子节点都是黑色的(空节点是视为黑色的)

二、红黑树的实现

2.1 红黑树节点的定义

红黑树的节点与AVL树相像,不过它是由节点颜色来维持平衡的,因此我们用枚举常量来表示节点的颜色,默认节点颜色为红色,这是为了保证每条路径上黑色节点的数量相同

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

2.2 红黑树节点的插入 

        由于要满足每条路径上黑色节点的数量相同,在插入节点时要将其设为红色,但是又要保证这个红色节点的孩子不能是红色,所以它的父亲如果是红色要变为黑,此时如果它的uncle节点(即与父亲节点有共同的parent)也存在并且也为红色需要将uncle也变为黑,然后继续向上处理。如果uncle不存在或者为黑色,则是第二种情况,接下俩我们具体来看看图。

2.2.1 uncle存在且为红

        此时我们要将parent和uncle都变为黑色,再把grandfather变为红色,因为这样才能保证每条路径上黑色节点的数量相同

        但这只是暂时解决了问题,如图,这里grandfather的parent也为红色了,不满足红黑树的性质,因此我们要根据情况继续向上处理:

  1. grandfather没有父亲,就是根,只需将它变黑即可
  2. grandfather有父亲且为黑色,那就不需要再调整了
  3. grandfather有父亲但为红色,这不就和正在处理的问题是类似的,如下图

2.2.2 uncle不存在

        如上图,uncle不存在,我们对grandfather进行右旋(如果parent在grandfather的右则进行的是左旋),再把parent变为黑色,grandfather变为红色即可。当然这里的cur如果插入在parent的右边,则需进行左右双旋,然后把cur变为黑色,grandfather变为红色即可。

2.2.3 uncle存在为黑色

其处理方式和uncle不存在是一样的,都是旋转+变色,这里就不过多阐述了。

2.3 总体代码实现

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 (parent->_kv.first < kv.first)
		{
			parent->_right = cur;
		}
		else
		{
			parent->_left = cur;
		}
		cur->_parent = parent;
		//插入后调整颜色
		while (parent && parent->_col == RED)
		{
			Node* grandfather = parent->_parent;
			//父在左的情况
			if (parent == grandfather->_left)
			{
				Node* uncle = grandfather->_right;
				//uncle存在且为红,parent和uncle变黑色,然后继续向上处理
				if (uncle && uncle->_col == RED)
				{
					//变色
					uncle->_col = parent->_col = BLACK;
					//把g改为红色(当成cur)
					grandfather->_col = RED;
					//继续向上调整
					cur = grandfather;
					parent = cur->_parent;
				}
				else     //uncle不存在或者为黑,旋转+变色
				{
					if (cur == parent->_left)
					{
						//       g
						//      p
						//    c
						RotateR(grandfather);
						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					else
					{
						//        g
						//      p
						//        c
						RotateL(parent);
						RotateR(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}
					break;
				}

			}
			//父在右的情况
			else   //  parent == grandfather->_left
			{
				Node* uncle = grandfather->_left;
				//uncle存在且为红,parent和uncle变黑色,然后继续向上处理
				if (uncle && uncle->_col == RED)
				{
					//变色
					uncle->_col = parent->_col = BLACK;
					//把g改为红色(当成cur)
					grandfather->_col = RED;
					//继续向上调整
					cur = grandfather;
					parent = cur->_parent;
				}
				else     //uncle不存在或者为黑,旋转+变色
				{
					if (cur == parent->_right)
					{
						//       g
						//		   p
						//			 c
						RotateL(grandfather);
						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					else
					{
						//        g
						//          p
						//        c
						RotateR(parent);
						RotateL(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}
					break;
				}

			}
		}
		_root->_col = BLACK;
		return true;
	}
	void RotateL(Node* parent)
	{
		++_rotateCount;
		Node* cur = parent->_right;
		Node* curleft = cur->_left;
		parent->_right = curleft;
		if (curleft)
		{
			curleft->_parent = parent;
		}
		cur->_left = parent;
		Node* ppnode = parent->_parent;
		parent->_parent = cur;
		if (parent == _root)
		{
			_root = cur;
			cur->_parent = nullptr;
		}
		else
		{
			if (ppnode->_left == parent)
			{
				ppnode->_left = cur;
			}
			else
			{
				ppnode->_right = cur;
			}
			cur->_parent = ppnode;
		}
		//parent->_bf = cur->_bf = 0;
	}
	void RotateR(Node* parent)
	{
		++_rotateCount;
		Node* cur = parent->_left;
		Node* curright = cur->_right;
		parent->_left = curright;
		if (curright)
		{
			curright->_parent = parent;
		}
		cur->_right = parent;
		Node* ppnode = parent->_parent;
		parent->_parent = cur;
		if (parent == _root)
		{
			_root = cur;
			cur->_parent = nullptr;
		}
		else
		{
			if (ppnode->_left == parent)
			{
				ppnode->_left = cur;
			}
			else
			{
				ppnode->_right = cur;
			}
			cur->_parent = ppnode;
		}
		//parent->_bf = cur->_bf = 0;
	}
	
	//检验RBL
	bool CheckColour(Node* root, int blacknum, int benchmark)
	{
		if (root == nullptr)
		{
			if (blacknum != benchmark)
			{
				return false;
			}
			return true;
		}
		if (root->_col == BLACK)
		{
			++blacknum;
		}
		if (root->_col == RED && root->_parent && root->_parent->_col == RED)
		{
			cout << root->_kv.first << "出现连续红色节点" << endl;
			return false;
		}
		return CheckColour(root->_left, blacknum, benchmark)
			&& CheckColour(root->_right, blacknum, benchmark);
	}
	bool isRBTree()
	{
		return isRBTree(_root);
	}
	bool isRBTree(Node* root)
	{
		if (root == nullptr)
		{
			return true;
		}
		if (root->_col != BLACK)
		{
			return false;
		}
		//基准值
		int benchmark = 0;
		Node* cur = _root;
		while (cur)
		{
			if (cur->_col == BLACK)
			{
				++benchmark;
			}
			cur = cur->_left;
		}
		return CheckColour(root, 0,benchmark);
		
	}
	int Height()
	{
		return Height(_root);
	}
	int Height(Node* root)
	{
		if (root == nullptr)
		{
			return 0;
		}
		int leftHeight = Height(root->_left);
		int rightHeight = Height(root->_right);
		return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
	}

private:
	Node* _root = nullptr;
public:
	int _rotateCount = 0;
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值