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

文章目录

  • 红黑树的概念
  • 红黑树的性质
  • 红黑树节点的结构
  • 红黑树的插入
    • 插入新节点
    • 更新整体节点的颜色
    • 插入的整体代码
    • 旋转处理
      • 右旋
      • 左旋
      • 右左双旋
      • 左右双旋
  • 红黑树的整体代码

红黑树的概念

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

红黑树的性质

【C++进阶】红黑树的实现_第2张图片

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

红黑树节点的结构

实现的是KV模型
节点的颜色用枚举值表示
【C++进阶】红黑树的实现_第3张图片

红黑树的插入

分三个步骤
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,继续向上调整。
【C++进阶】红黑树的实现_第4张图片
如果向上更新的过程中,parent节点为黑或者已经更新到了根节点说明子树已经满足了红黑树的规则就停止更新,否则继续向上更新。
【C++进阶】红黑树的实现_第5张图片

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存在且为黑
【C++进阶】红黑树的实现_第6张图片
小情况1:u不存在
【C++进阶】红黑树的实现_第7张图片

小情况2:u存在且为黑
由上面的情况一向上调整的过程中变成的
【C++进阶】红黑树的实现_第8张图片
解决方法
p为g的左孩子,cur为p的左孩子,则进行右单旋转;
相反p为g的右孩子,cur为p的右孩子,则进行左单旋转
p、g变色--p变黑,g变红
【C++进阶】红黑树的实现_第9张图片
【C++进阶】红黑树的实现_第10张图片
右旋

//单旋
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不存在
【C++进阶】红黑树的实现_第11张图片
小情况2:u存在且为黑
由上面的情况一向上调整的过程中变成的
【C++进阶】红黑树的实现_第12张图片
解决方法:
p为g的左孩子,cur为p的右孩子,则针对p做左单旋转;
相反,p为g的右孩子,cur为p的左孩子,则针对p做右单旋转
则转换成了情况二,然后再由情况二进行旋转调整变成符合规则的红黑树
说明进行了两次旋转:右左双旋或者左右双旋
【C++进阶】红黑树的实现_第13张图片
【C++进阶】红黑树的实现_第14张图片
左右双旋

//双旋
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;*/
	}
}

你可能感兴趣的:(C++初阶和高阶,c++,开发语言)