【C++进阶】红黑树的实现

红黑树的概念

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

红黑树的性质

在这里插入图片描述

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

红黑树节点的结构

实现的是KV模型
节点的颜色用枚举值表示
在这里插入图片描述

红黑树的插入

分三个步骤
1.按二叉搜索树的规则插入数据
2.更新整体节点的颜色
3.更新颜色的过程中判断是否需要旋转

插入新节点

bool Insert(const pair<K, V>& kv)
{
	Node* parent = nullptr;
	Node* cur = _root;

	//如果根为空
	if (_root == nullptr)
	{
		_root = new Node(kv);
		_root->_col = BLACK;
		return true;
	}

	//寻找插入位置
	while (cur)
	{
		//如果要插入的值比cur的值小
		if (cur->_kv.first > kv.first)
		{
			//往左找
			parent = cur;
			cur = cur->_left;
		}
		//如果要插入的值比cur的值大
		else if (cur->_kv.first < kv.first)
		{
			//往右找
			parent = cur;
			cur = cur->_right;
		}
		//如果相等就不再插入
		else
		{
			return false;
		}
	}

	//插入
	cur = new Node(kv);
	if (parent->_kv.first > kv.first)
	{
		parent->_left = cur;
		cur->_parent = parent;
	}
	else
	{
		parent->_right = cur;
		cur->_parent = parent;
	}
}

更新整体节点的颜色

因为新节点的默认颜色是红色,因此:如果其双亲节点的颜色是黑色,没有违反红黑树任何 性质,则不需要调整;但当新插入节点的双亲节点颜色为红色时,就违反了性质三不能有连
在一起的红色节点,此时需要对红黑树分情况来讨论
约定:cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点

情况一:cur为红,p为红,g为黑,u存在且为红
解决方式:将p,u改为黑,g改为红,然后把g当成cur,继续向上调整。
在这里插入图片描述
如果向上更新的过程中,parent节点为黑或者已经更新到了根节点说明子树已经满足了红黑树的规则就停止更新,否则继续向上更新。
在这里插入图片描述

if (uncle && uncle->_col == RED)
{
	parent->_col = BLACK;
	uncle->_col = BLACK;
	grandpa->_col = RED;

	cur = grandpa;
	parent = cur->_parent;
}

代码只展示了一次更新的结果,会在while循环不断往上更新直到满足红黑树的规则

情况二: cur为红,p为红,g为黑,u不存在/u存在且为黑
在这里插入图片描述
小情况1:u不存在
在这里插入图片描述

小情况2:u存在且为黑
由上面的情况一向上调整的过程中变成的
在这里插入图片描述
解决方法
p为g的左孩子,cur为p的左孩子,则进行右单旋转;
相反p为g的右孩子,cur为p的右孩子,则进行左单旋转
p、g变色--p变黑,g变红
在这里插入图片描述
在这里插入图片描述
右旋

//单旋
if (parent->_left == cur)
{
	RotateR(grandpa);
	parent->_col = BLACK;
	grandpa->_col = RED;
}

左旋

//单旋
if (parent->_right == cur)
{
	RotateL(grandpa);
	parent->_col = BLACK;
	grandpa->_col = RED;
}

情况三: cur为红,p为红,g为黑,u不存在/u存在且为黑
小情况1:u不存在
在这里插入图片描述
小情况2:u存在且为黑
由上面的情况一向上调整的过程中变成的
在这里插入图片描述
解决方法:
p为g的左孩子,cur为p的右孩子,则针对p做左单旋转;
相反,p为g的右孩子,cur为p的左孩子,则针对p做右单旋转
则转换成了情况二,然后再由情况二进行旋转调整变成符合规则的红黑树
说明进行了两次旋转:右左双旋或者左右双旋
在这里插入图片描述
在这里插入图片描述
左右双旋

//双旋
else
{
	RotateLR(grandpa);
	grandpa->_col = RED;
	cur->_col = BLACK;
}

右左双旋

//双旋
else
{
	RotateRL(grandpa);
	cur->_col = BLACK;
	grandpa->_col = RED;
}

插入的整体代码

bool Insert(const pair<K, V>& kv)
{
	Node* parent = nullptr;
	Node* cur = _root;

	//如果根为空
	if (_root == nullptr)
	{
		_root = new Node(kv);
		_root->_col = BLACK;
		return true;
	}

	//寻找插入位置
	while (cur)
	{
		//如果要插入的值比cur的值小
		if (cur->_kv.first > kv.first)
		{
			//往左找
			parent = cur;
			cur = cur->_left;
		}
		//如果要插入的值比cur的值大
		else if (cur->_kv.first < kv.first)
		{
			//往右找
			parent = cur;
			cur = cur->_right;
		}
		//如果相等就不再插入
		else
		{
			return false;
		}
	}

	//插入
	cur = new Node(kv);
	if (parent->_kv.first > kv.first)
	{
		parent->_left = cur;
		cur->_parent = parent;
	}
	else
	{
		parent->_right = cur;
		cur->_parent = parent;
	}

	//更新颜色
	while (parent && parent->_col == RED)
	{
		Node* grandpa = parent->_parent;
		Node* uncle = nullptr;
		if (grandpa->_left == parent)
		{
			uncle = grandpa->_right;
			if (uncle && uncle->_col == RED)
			{
				parent->_col = BLACK;
				uncle->_col = BLACK;
				grandpa->_col = RED;

				cur = grandpa;
				parent = cur->_parent;
			}
			else
			{
				//单旋
				if (parent->_left == cur)
				{
					RotateR(grandpa);
					parent->_col = BLACK;
					grandpa->_col = RED;
				}
				//双旋
				else
				{
					RotateLR(grandpa);
					grandpa->_col = RED;
					cur->_col = BLACK;
				}
				break;
			}
		}
		else
		{
			uncle = grandpa->_left;
			if (uncle && uncle->_col == RED)
			{
				parent->_col = BLACK;
				uncle->_col = BLACK;
				grandpa->_col = RED;

				cur = grandpa;
				parent = cur->_parent;
			}
			else
			{
				//单旋
				if (parent->_right == cur)
				{
					RotateL(grandpa);
					parent->_col = BLACK;
					grandpa->_col = RED;
				}
				//双旋
				else
				{
					RotateRL(grandpa);
					cur->_col = BLACK;
					grandpa->_col = RED;
				}
				break;
			}
					
		}

	}
	_root->_col = BLACK;
	return true;
}

旋转处理

这边的旋转方法和我之前的博客AVL树里面的旋转方法一样,便不再过多叙述,主要放代码

右旋

void RotateR(Node* parent)
{
	//要调整的节点
	Node* sub = parent;
	//要调整的节点的左孩子
	Node* subL = parent->_left;
	//要调整的节点的左孩子的右孩子
	Node* subLR = subL->_right;

	//要调整的节点的父母
	Node* subparent = sub->_parent;

	//重新链接关系
	if (subLR)
		subLR->_parent = sub;
	sub->_left = subLR;

	sub->_parent = subL;
	subL->_right = sub;

	subL->_parent = subparent;

	if (_root == sub)
	{
		_root = subL;
	}
	else
	{
		if (subparent->_left == sub)
		{
			subparent->_left = subL;
		}
		else
		{
			subparent->_right = subL;
		}
	}

}

左旋

void RotateL(Node* parent)
{
	//要调整的节点
	Node* sub = parent;
	//要调整的节点的右孩子
	Node* subR = parent->_right;
	//要调整的节点的有孩子的左孩子
	Node* subRL = subR->_left;

	//要调整的节点的父母
	Node* subparent = sub->_parent;

	//重新链接关系
	if (subRL)
		subRL->_parent = sub;
	sub->_right = subRL;

	sub->_parent = subR;
	subR->_left = sub;

	subR->_parent = subparent;

	if (_root == sub)
	{
		_root = subR;
	}
	else
	{
		if (subparent->_left == sub)
		{
			subparent->_left = subR;
		}
		else
		{
			subparent->_right = subR;
		}
	}
}

右左双旋

void RotateRL(Node* parent)
{
	RotateR(parent->_right);
	RotateL(parent);
}

左右双旋

void RotateLR(Node* parent)
{
	RotateL(parent->_left);
	RotateR(parent);
			
}

红黑树的整体代码

#pragma once
namespace lzf
{
	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;//该节点要存储的值

		int _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:
		RBTree()
			:_root(nullptr)
		{}
		bool Insert(const pair<K, V>& kv)
		{
			Node* parent = nullptr;
			Node* cur = _root;

			//如果根为空
			if (_root == nullptr)
			{
				_root = new Node(kv);
				_root->_col = BLACK;
				return true;
			}

			//寻找插入位置
			while (cur)
			{
				//如果要插入的值比cur的值小
				if (cur->_kv.first > kv.first)
				{
					//往左找
					parent = cur;
					cur = cur->_left;
				}
				//如果要插入的值比cur的值大
				else if (cur->_kv.first < kv.first)
				{
					//往右找
					parent = cur;
					cur = cur->_right;
				}
				//如果相等就不再插入
				else
				{
					return false;
				}
			}

			//插入
			cur = new Node(kv);
			if (parent->_kv.first > kv.first)
			{
				parent->_left = cur;
				cur->_parent = parent;
			}
			else
			{
				parent->_right = cur;
				cur->_parent = parent;
			}

			//更新颜色
			while (parent && parent->_col == RED)
			{
				Node* grandpa = parent->_parent;
				Node* uncle = nullptr;
				if (grandpa->_left == parent)
				{
					uncle = grandpa->_right;
					if (uncle && uncle->_col == RED)
					{
						parent->_col = BLACK;
						uncle->_col = BLACK;
						grandpa->_col = RED;

						cur = grandpa;
						parent = cur->_parent;
					}
					else
					{
						//单旋
						if (parent->_left == cur)
						{
							RotateR(grandpa);
							parent->_col = BLACK;
							grandpa->_col = RED;
						}
						//双旋
						else
						{
							RotateLR(grandpa);
							grandpa->_col = RED;
							cur->_col = BLACK;
						}
						break;
					}
				}
				else
				{
					uncle = grandpa->_left;
					if (uncle && uncle->_col == RED)
					{
						parent->_col = BLACK;
						uncle->_col = BLACK;
						grandpa->_col = RED;

						cur = grandpa;
						parent = cur->_parent;
					}
					else
					{
						//单旋
						if (parent->_right == cur)
						{
							RotateL(grandpa);
							parent->_col = BLACK;
							grandpa->_col = RED;
						}
						//双旋
						else
						{
							RotateRL(grandpa);
							cur->_col = BLACK;
							grandpa->_col = RED;
						}
						break;
					}
					
				}

			}
			_root->_col = BLACK;
			return true;
		}
		void InOrder()
		{
			_InOrder(_root);
		}
		bool IsRBTree()
		{
			if (_root&& _root->_col == RED)
			{
				return false;
			}

			int blackmark = 0;
			Node* left = _root;
			while (left)
			{
				if (left->_col == BLACK)
				{
					blackmark++;
				}
				left = left->_left;
			}
			int blacknum = 0;
			return _IsRBTree(_root, blackmark, blacknum);
		}
	private:
		void RotateR(Node* parent)
		{
			//要调整的节点
			Node* sub = parent;
			//要调整的节点的左孩子
			Node* subL = parent->_left;
			//要调整的节点的左孩子的右孩子
			Node* subLR = subL->_right;

			//要调整的节点的父母
			Node* subparent = sub->_parent;

			//重新链接关系
			if (subLR)
				subLR->_parent = sub;
			sub->_left = subLR;

			sub->_parent = subL;
			subL->_right = sub;

			subL->_parent = subparent;

			if (_root == sub)
			{
				_root = subL;
			}
			else
			{
				if (subparent->_left == sub)
				{
					subparent->_left = subL;
				}
				else
				{
					subparent->_right = subL;
				}
			}

		}
		void RotateL(Node* parent)
		{
			//要调整的节点
			Node* sub = parent;
			//要调整的节点的右孩子
			Node* subR = parent->_right;
			//要调整的节点的有孩子的左孩子
			Node* subRL = subR->_left;

			//要调整的节点的父母
			Node* subparent = sub->_parent;

			//重新链接关系
			if (subRL)
				subRL->_parent = sub;
			sub->_right = subRL;

			sub->_parent = subR;
			subR->_left = sub;

			subR->_parent = subparent;

			if (_root == sub)
			{
				_root = subR;
			}
			else
			{
				if (subparent->_left == sub)
				{
					subparent->_left = subR;
				}
				else
				{
					subparent->_right = subR;
				}
			}
		}
		void RotateRL(Node* parent)
		{
			RotateR(parent->_right);
			RotateL(parent);
		}
		void RotateLR(Node* parent)
		{
			RotateL(parent->_left);
			RotateR(parent);
			
		}
		void _InOrder(Node* root)
		{
			if (root == nullptr)
			{
				return;
			}
			_InOrder(root->_left);
			cout << root->_kv.first << ":" << root->_kv.second << endl;
			_InOrder(root->_right);
		}
		bool _IsRBTree(Node* root, int blackmark, int blacknum)
		{
			if (root == nullptr)
			{
				if (blackmark != blacknum)
				{
					return false;
				}
				return true;
			}

			if (root->_col == RED && root->_parent->_col == RED)
			{
				return false;
			}

			if (root->_col == BLACK)
			{
				blacknum++;
			}
			return _IsRBTree(root->_left, blackmark, blacknum)
				&& _IsRBTree(root->_right, blackmark, blacknum);

		}
	private:
		Node* _root;
	};

	void Test_RBTree()
	{
		RBTree<int, int> tree;
		tree.Insert(make_pair(5, 5));
		tree.Insert(make_pair(3, 3));
		tree.Insert(make_pair(8, 8));
		tree.Insert(make_pair(4, 4));
		tree.Insert(make_pair(6, 6));
		tree.Insert(make_pair(2, 2));
		tree.Insert(make_pair(7, 7));

		tree.InOrder();
		cout << tree.IsRBTree();
	}

	void Test_RBTree2()
	{
		RBTree<int, int> t;
		int a[] = {5,4,3,2,1,0};
		//int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
		/*int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };*/
		for (auto e : a)
		{
			t.Insert(make_pair(e, e));
			cout << "Insert" << e << ":" << t.IsRBTree() << endl;
		}
		t.InOrder();
		cout << t.IsRBTree() << endl;
	}

	void TestRBTree()
	{
		RBTree<int, int> t;
		vector<int> v;
		srand(time(0));
		int N = 10000;
		for (int i = 0; i < N; ++i)
		{
			//v.push_back(rand());
			v.push_back(i);
		}
		//int a[] = {5,4,3,2,1,0};
		//int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
		//int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
		for (auto e : v)
		{
			t.Insert(make_pair(e, e));
			if (!t.IsRBTree())
			{
			cout << "Insert" << e << endl;
			}
		}
		//t.InOrder();
		cout << t.IsRBTree() << endl;
		/*cout << "高度:" << t.IsRBTree() << endl;*/
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当然,我可以帮你实现一个基于红黑树的Map数据结构。下面是一个简单的C++代码示例: ```cpp #include <iostream> enum Color { RED, BLACK }; template <typename K, typename V> struct Node { K key; V value; Color color; Node* left; Node* right; Node* parent; // 构造函数 Node(const K& k, const V& v, Color c = RED) : key(k), value(v), color(c), left(nullptr), right(nullptr), parent(nullptr) {} }; template <typename K, typename V> class RBTreeMap { public: RBTreeMap() : root(nullptr) {} // 向红黑树中插入键值对 void insert(const K& key, const V& value) { Node<K, V>* node = new Node<K, V>(key, value); if (root == nullptr) { root = node; node->color = BLACK; } else { Node<K, V>* curr = root; Node<K, V>* parent = nullptr; while (curr != nullptr) { parent = curr; if (key < curr->key) curr = curr->left; else if (key > curr->key) curr = curr->right; else { curr->value = value; // 更新值 return; } } node->parent = parent; if (key < parent->key) parent->left = node; else parent->right = node; insertFixup(node); } } // 查找指定键的值 V find(const K& key) const { Node<K, V>* curr = root; while (curr != nullptr) { if (key < curr->key) curr = curr->left; else if (key > curr->key) curr = curr->right; else return curr->value; } return V(); // 未找到,返回默认值 } private: Node<K, V>* root; // 对红黑树进行修复以维持红黑树的性质 void insertFixup(Node<K, V>* node) { while (node->parent != nullptr && node->parent->color == RED) { if (node->parent == node->parent->parent->left) { Node<K, V>* uncle = node->parent->parent->right; if (uncle != nullptr && uncle->color == RED) { node->parent->color = BLACK; uncle->color = BLACK; node->parent->parent->color = RED; node = node->parent->parent; } else { if (node == node->parent->right) { node = node->parent; rotateLeft(node); } node->parent->color = BLACK; node->parent->parent->color = RED; rotateRight(node->parent->parent); } } else { Node<K, V>* uncle = node->parent->parent->left; if (uncle != nullptr && uncle->color == RED) { node->parent->color = BLACK; uncle->color = BLACK; node->parent->parent->color = RED; node = node->parent->parent; } else { if (node == node->parent->left) { node = node->parent; rotateRight(node); } node->parent->color = BLACK; node->parent->parent->color = RED; rotateLeft(node->parent->parent); } } } root->color = BLACK; } // 左旋 void rotateLeft(Node<K, V>* node) { Node<K, V>* rightChild = node->right; node->right = rightChild->left; if (rightChild->left != nullptr) rightChild->left->parent = node; rightChild->parent = node->parent; if (node->parent == nullptr) root = rightChild; else if (node == node->parent->left) node->parent->left = rightChild; else node->parent->right = rightChild; rightChild->left = node; node->parent = rightChild; } // 右旋 void rotateRight(Node<K, V>* node) { Node<K, V>* leftChild = node->left; node->left = leftChild->right; if (leftChild->right != nullptr) leftChild->right->parent = node; leftChild->parent = node->parent; if (node->parent == nullptr) root = leftChild; else if (node == node->parent->left) node->parent->left = leftChild; else node->parent->right = leftChild; leftChild->right = node; node->parent = leftChild; } }; int main() { RBTreeMap<int, std::string> map; map.insert(1, "one"); map.insert(2, "two"); map.insert(3, "three"); map.insert(4, "four"); std::cout << map.find(2) << std::endl; // 输出: two std::cout << map.find(5) << std::endl; // 输出: 空字符串(默认值) return 0; } ``` 这个示例使用红黑树实现了一个简单的Map数据结构。你可以使用`insert`方法向Map中插入键值对,使用`find`方法查找指定键的值。注意,这只是一个简单的实现,还可以根据需要进行扩展和优化。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值