C++ | 红黑树的规则及其插入过程的讲解与实现

红黑树概念

总特征:任意节点到叶子节点的最长路径不超过最短路径的两倍

1.每个节点非红即黑
2.根节点为黑色
3.如果一个节点为红色,那么它的子节点必须是黑色(不能有连续的红节点)
4.对于某个节点来说,该节点到所有叶子节点的路径上的黑色节点数量相同

在这里插入图片描述
图片来自百度百科

话不多说,直接用C++实现红黑树的结构

整体结构

enum Colour
{
	RED,
	BLACK
};


template <class K, class V>
struct RBTreeNode
{
	pair<K, V> _kv;
	RBTreeNode* _left;
	RBTreeNode* _right;
	RBTreeNode* _parent;
	Colour _col;

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

template <class K, class V>
class RBTree
{
	typedef RBTreeNode<K, V> Node;
public:
	bool Insert(const pair<K, V>& kv);
	bool IsRBTree();
	void Inorder() { _Inorder(_root); }
	void Leorder() { _Leorder(_root); }
private:
	void RotateL(Node* root);
	void RotateR(Node* root);
	int _HeightGreater(Node* root);
	int _HeightLess(Node* root);
	bool _IsRBTree(Node* root, int k, int blackCount);
	void _Inorder(Node* root);
	void _Leorder(Node* root);
private:
	Node* _root = nullptr;
};

插入的三种情况

插入节点颜色都是红色,因为如果插入节点为黑色,一定不符合任意节点到其所有叶子节点的黑色节点数量相同的规则,但插入节点为红色,可以根据红黑树的规则进行一定的调整,使其重新满足红黑树的性质

g是祖父节点,p是父节点,u是叔叔节点,cur可能是当前插入节点,也可能是a或b子树调整后的祖父节点

关于其中涉及到的旋转,在AVL的插入讲解这篇博客中有详细介绍

情况1

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

第一种情况:

  • 如果p与u都是红色,将p与u改为黑色,g改为红色
  • 如果g的父节点为黑(g可能是整棵树中的子树),调整结束
  • 如果g的父节点为红,需要以g为cur向上继续调整
  • 同理,如果p和u的位置调换,但u为红色,也是这样调整(就是上面的四种情况

最后:

  • 如果子树的根节点g为树的根节点,将其改为黑,退出更新
  • 如果不是,则判断g的父节点是否为红
    • 如果为红,将g作为新的cur,并且根据cur的位置更新出g,u,p的位置,根据情况继续进行更新
    • 如果为黑,则退出更新

情况2

在这里插入图片描述
在这里插入图片描述

第二种情况:

  • 如果u不存在,cur就是新插入的节点,以g为根节点进行右旋转(p为g的右子节点则进行左旋转),最后将p和g的颜色反转
  • 如果u存在且为黑,那么cur不是新插入的节点,cur之前为黑(因为p为红,cur不可能为红),因为cur的子树调整导致了cur变红。这种情况下,调整方法与第一种是一样的。
    为什么第一种情况可以直接将p和u变为黑
  • 因为这样做不违反每条路径上的黑节点数量相同的规则,u和p都为红的情况下,将一条路径上的两节点颜色反转,所有路径的黑色节点的数量没有发生变化
  • 但在u为黑的情况下,将p和u变黑,因为u本来就是黑的,所以只有某些路径的黑色节点数量增加,违反了第四条这个规则

总结

  • 只有在出现连续两个节点为红色时,才会进行调整。所以cur和parent一定为红
  • 三种情况的判断关键在于:uncle节点的颜色
  • 若u为红,则反转u,p和g的颜色,对应第一种情况
  • 若u为黑,需要进行旋转以维持第四条规则,对应第二和三种情况

情况3

在这里插入图片描述
在这里插入图片描述

第三种情况:

  • u为黑或不存在,p为g的左子节点,cur为p的右子节点
  • 思路是往情况2靠,以cur为根节点进行左单旋,成为情况2,以情况2的方式旋转,变色
  • 同理,p为g的右子节点,cur为p的左子节点,也是一样的

Insert代码

template <class K, class V>
bool RBTree<K, V>::Insert(const pair<K, V>& kv)
{
	// 以搜索二叉树的规则插入
	if (_root == nullptr)
	{
		_root = new Node(kv);
		// 根节点为黑色
		_root->_col = BLACK;
		return true;
	}

	Node* cur = _root;
	Node* parent = nullptr;
	// 找合适的插入位置
	while (cur)
	{
		if (kv.first < cur->_kv.first)
		{
			parent = cur;
			cur = cur->_left;
		}
		else if (kv.first > cur->_kv.first)
		{
			parent = cur;
			cur = cur->_right;
		}
		else
		{
			return false;
		}
	}
	cur = new Node(kv);
	// 判断该插入parent的哪边
	if (kv.first < parent->_kv.first)
	{
		parent->_left = cur;
	}
	else
	{
		parent->_right = cur;
	}
	cur->_parent = parent;
	// 插入结束

	// 保持平衡
	while (parent && parent->_col == RED) // 出现连续的红节点
	{
		Node* grandParent = parent->_parent;
		assert(grandParent);

		if (grandParent->_left == parent) // parent在祖父节点左边
		{
			Node* uncle = grandParent->_right;
			// u为红色,一定要提前判断u是否存在
			if (uncle && uncle->_col == RED)
			{
				uncle->_col = BLACK;
				parent->_col = BLACK;
				grandParent->_col = RED;
				if (grandParent == _root)
				{
					grandParent->_col = BLACK;
					return true;
				}
				else // grandParent不是根节点,但其父节点为黑色,也插入完成
				{
					if (grandParent->_parent && grandParent->_parent->_col == BLACK)
					{
						return true;
					}
					else // grandParent的父节点为红,出现连续红节点,更新节点,继续调整
					{
						cur = grandParent;
						parent = cur->_parent;
					}
				}
			} // end of if (uncle && uncle->_col == RED)

			else // u不存在或者为黑
			{
				// cur在p的左边
				if (cur == parent->_left)
				{
					RotateR(grandParent);
					grandParent->_col = RED;
					parent->_col = BLACK;
				}
				else // cur在p的右边,需要旋转成左边的情况
				{
					RotateL(parent);
					RotateR(grandParent);
					cur->_col = BLACK;
					grandParent->_col = RED;
				}
				return true;
			}
		} // end of - if (grandParent->_left == parent)

		else // p在grandParent的右边
		{
			Node* uncle = grandParent->_left;
			assert(grandParent);
			// u为红色
			if (uncle && uncle->_col == RED)
			{
				uncle->_col = BLACK;
				parent->_col = BLACK;
				grandParent->_col = RED;
				if (grandParent == _root)
				{
					_root->_col = BLACK;
					return true;
				}
				else
				{
					if (grandParent->_parent && grandParent->_parent->_col == BLACK)
					{
						return true;
					}
					// 更新继续调整
					else
					{
						cur = grandParent;
						parent = cur->_parent;
					}
				}
			} // end of if (uncle && uncle->_col == RED)

			else // u不存在或者为黑
			{
				// cur在p的右边
				if (cur == parent->_right)
				{
					RotateL(grandParent);
					grandParent->_col = RED;
					parent->_col = BLACK;
				}
				else // cur在p的右边,需要旋转成左边的情况
				{
					RotateR(parent);
					RotateL(grandParent);
					cur->_col = BLACK;
					grandParent->_col = RED;
				}
				return true;
			}
		} // end of - else
	}// end if - while
	return true;
}

验证红黑树

先求出一条路径上的黑色节点数量blackCount,然后调用子函数,子函数递归整棵树,用k记录当前路径的黑色节点数量,遇到黑色节点k++,当遇到节点为空的情况,比较k与blackCount是否相等。

另外每次递归要判断

  1. 根节点是否是黑色
  2. 如果该节点为红色,且父节点存在,如果父节点也为红,不满足红黑树性质
  3. 求出节点到叶子节点的最短路径与最长路径,判断最短路径的两倍不能小于最长路径
template <class K, class V>
bool RBTree<K, V>::_IsRBTree(Node* cur, int k, int blackCount)
{
	if (cur == nullptr)
	{
		if (blackCount != k)
		{
			cout << "路径上的黑色节点数量不相等" << endl;
			return false;
		}
		return true;
	}
	if (_root->_col != BLACK)
	{
		cout << "根节点为红色" << endl;
		return false;
	}

	// 求以cur为根节点的最小高度与最大高度
	int less = _HeightLess(cur);
	int greater = _HeightGreater(cur);

	if (less * 2 < greater)
	{
		cout << "最长路径超过最短路径两倍" << endl;
		return false;
	}

	if (cur->_col == RED && cur->_parent && cur->_parent->_col == RED)
	{
		cout << "出现连续红色节点" << endl;
		return false; // 检查连续的红色节点
	}

	if (cur->_col == BLACK)
	{
		k++;
	}

	// 递归验证左右子树
	return _IsRBTree(cur->_left, k, blackCount) && _IsRBTree(cur->_right, k, blackCount);
}

在这里插入图片描述

hpp所有代码

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;
#include <utility>
#include <assert.h>
#include <queue>
enum Colour
{
	RED,
	BLACK
};


template <class K, class V>
struct RBTreeNode
{
	pair<K, V> _kv;
	RBTreeNode* _left;
	RBTreeNode* _right;
	RBTreeNode* _parent;
	Colour _col;

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

template <class K, class V>
class RBTree
{
	typedef RBTreeNode<K, V> Node;
public:
	bool Insert(const pair<K, V>& kv);
	bool IsRBTree();
	void Inorder() { _Inorder(_root); }
	void Leorder() { _Leorder(_root); }
private:
	void RotateL(Node* root);
	void RotateR(Node* root);
	int _HeightGreater(Node* root);
	int _HeightLess(Node* root);
	bool _IsRBTree(Node* root, int k, int blackCount);
	void _Inorder(Node* root);
	void _Leorder(Node* root);
private:
	Node* _root = nullptr;
};

template <class K, class V>
bool RBTree<K, V>::Insert(const pair<K, V>& kv)
{
	// 以搜索二叉树的规则插入
	if (_root == nullptr)
	{
		_root = new Node(kv);
		// 根节点为黑色
		_root->_col = BLACK;
		return true;
	}

	Node* cur = _root;
	Node* parent = nullptr;
	// 找合适的插入位置
	while (cur)
	{
		if (kv.first < cur->_kv.first)
		{
			parent = cur;
			cur = cur->_left;
		}
		else if (kv.first > cur->_kv.first)
		{
			parent = cur;
			cur = cur->_right;
		}
		else
		{
			return false;
		}
	}
	cur = new Node(kv);
	// 判断该插入parent的哪边
	if (kv.first < parent->_kv.first)
	{
		parent->_left = cur;
	}
	else
	{
		parent->_right = cur;
	}
	cur->_parent = parent;
	// 插入结束

	// 保持平衡
	while (parent && parent->_col == RED) // 出现连续的红节点
	{
		Node* grandParent = parent->_parent;
		assert(grandParent);

		if (grandParent->_left == parent) // parent在祖父节点左边
		{
			Node* uncle = grandParent->_right;
			// u为红色,一定要提前判断u是否存在
			if (uncle && uncle->_col == RED)
			{
				uncle->_col = BLACK;
				parent->_col = BLACK;
				grandParent->_col = RED;
				if (grandParent == _root)
				{
					grandParent->_col = BLACK;
					return true;
				}
				else // grandParent不是根节点,但其父节点为黑色,也插入完成
				{
					if (grandParent->_parent && grandParent->_parent->_col == BLACK)
					{
						return true;
					}
					else // grandParent的父节点为红,出现连续红节点,更新节点,继续调整
					{
						cur = grandParent;
						parent = cur->_parent;
					}
				}
			} // end of if (uncle && uncle->_col == RED)

			else // u不存在或者为黑
			{
				// cur在p的左边
				if (cur == parent->_left)
				{
					RotateR(grandParent);
					grandParent->_col = RED;
					parent->_col = BLACK;
				}
				else // cur在p的右边,需要旋转成左边的情况
				{
					RotateL(parent);
					RotateR(grandParent);
					cur->_col = BLACK;
					grandParent->_col = RED;
				}
				return true;
			}
		} // end of - if (grandParent->_left == parent)

		else // p在grandParent的右边
		{
			Node* uncle = grandParent->_left;
			assert(grandParent);
			// u为红色
			if (uncle && uncle->_col == RED)
			{
				uncle->_col = BLACK;
				parent->_col = BLACK;
				grandParent->_col = RED;
				if (grandParent == _root)
				{
					_root->_col = BLACK;
					return true;
				}
				else
				{
					if (grandParent->_parent->_col == BLACK)
					{
						return true;
					}
					// 更新继续调整
					else
					{
						cur = grandParent;
						parent = cur->_parent;
					}
				}
			} // end of if (uncle && uncle->_col == RED)

			else // u不存在或者为黑
			{
				// cur在p的右边
				if (cur == parent->_right)
				{
					RotateL(grandParent);
					grandParent->_col = RED;
					parent->_col = BLACK;
				}
				else // cur在p的右边,需要旋转成左边的情况
				{
					RotateR(parent);
					RotateL(grandParent);
					cur->_col = BLACK;
					grandParent->_col = RED;
				}
				return true;
			}
		} // end of - else
	}// end if - while
	return true;
}



template <class K, class V>
void RBTree<K, V>::RotateL(Node* parent)
{
	Node* subR = parent->_right;
	Node* subRL = subR->_left;

	subR->_left = parent;
	parent->_right = subRL;

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

	if (subRL)
		subRL->_parent = parent;
	if (_root == parent)
	{
		_root = subR;
		subR->_parent = nullptr;
	}
	else // 该子树是树的一部分
	{
		subR->_parent = pparent;
		if (subR->_kv.first < pparent->_kv.first)
		{
			pparent->_left = subR;
		}
		else
		{
			pparent->_right = subR;
		}
	}
}

template <class K, class V>
void RBTree<K, V>::RotateR(Node* parent)
{
	Node* subL = parent->_left;
	Node* subLR = subL->_right;

	subL->_right = parent;
	parent->_left = subLR;

	Node* pparent = parent->_parent;
	parent->_parent = subL;

	if (subLR)
		subLR->_parent = parent;
	if (_root == parent)
	{
		_root = subL;
		subL->_parent = nullptr;
	}
	else
	{
		subL->_parent = pparent;
		if (subL->_kv.first < pparent->_kv.first)
		{
			pparent->_left = subL;
		}
		else
		{
			pparent->_right = subL;
		}
	}
}


template <class K, class V>
int RBTree<K, V>::_HeightGreater(Node* root)
{
	if (root == nullptr)
	{
		return 0;
	}

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

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

template <class K, class V>
int RBTree<K, V>::_HeightLess(Node* root)
{
	if (root == nullptr)
	{
		return 0;
	}

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

	return leftH < rightH ? 1 + leftH : 1 + rightH;
}
template <class K, class V>
bool RBTree<K, V>::IsRBTree()
{
	int blackCount = 0;
	Node* cur = _root;
	while (cur)
	{
		if (cur->_col == BLACK)
		{
			blackCount++;
		}
		cur = cur->_left;
	}
	int k = 0;

	return _IsRBTree(_root, k, blackCount);
}

template <class K, class V>
bool RBTree<K, V>::_IsRBTree(Node* cur, int k, int blackCount)
{
	if (cur == nullptr)
	{
		if (blackCount != k)
		{
			cout << "路径上的黑色节点数量不相等" << endl;
			return false;
		}
		return true;
	}
	if (_root->_col != BLACK)
	{
		cout << "根节点为红色" << endl;
		return false;
	}

	// 求以cur为根节点的最小高度与最大高度
	int less = _HeightLess(cur);
	int greater = _HeightGreater(cur);

	if (less * 2 < greater)
	{
		cout << "最长路径超过最短路径两倍" << endl;
		return false;
	}

	if (cur->_col == RED && cur->_parent && cur->_parent->_col == RED)
	{
		cout << "出现连续红色节点" << endl;
		return false; // 检查连续的红色节点
	}

	if (cur->_col == BLACK)
	{
		k++;
	}

	// 递归验证左右子树
	return _IsRBTree(cur->_left, k, blackCount) && _IsRBTree(cur->_right, k, blackCount);
}

template <class K, class V>
void RBTree<K, V>::_Inorder(Node* root)
{
	if (root == nullptr)
		return;

	_Inorder(root->_left);
	cout << root->_kv.first << ' ';
	_Inorder(root->_right);
}

template <class K, class V>
void RBTree<K, V>::_Leorder(Node* root)
{
	queue<Node*> q;
	q.push(root);
	int count = 1;
	while (!q.empty())
	{
		while (count)
		{
			Node* top = q.front();
			q.pop();
			count--;
			if (top)
			{
				q.push(top->_left);
				q.push(top->_right);
				cout << top->_col << ' ';
			}
			else
			{
				cout << "nullptr ";
			}
		}
		count = q.size();
		cout << endl;
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值