红黑树的插入底层【C++】

文章目录

  • 红黑树的概念
  • 红黑树的性质
  • 红黑树结点
  • Insert
  • CheckColour
  • IsBalance
  • 完整代码

红黑树的概念

红黑树是一种二叉搜索树,但在每个结点上增加了一个存储位用于表示结点的颜色,这个颜色可以是红色的,也可以是黑色的,因此我们称之为红黑树

红黑树通过对任何一条从根到叶子的路径上各个结点着色方式的限制,确保没有一条路径会比其他路径长出两倍,因此红黑树是近似平衡的

红黑树的插入底层【C++】_第1张图片

红黑树的性质

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

从根到叶子的最长可能路径不会超过最短可能路径的两倍,如何保证?

性质3推出红黑树中不会出现连续的红色结点,根据性质4推出,从某一结点到其后代叶子结点的所有路径上包含的黑色结点的数目是相同的

假设在红黑树中,从根到叶子的所有路径上包含的黑色结点的个数都是N 个

最短路径就是全部由黑色结点构成的路径,即长度为N

最长可能路径就是由一黑一红结点构成的路径,该路径当中黑色结点与红色结点的数目相同,即长度为2N

红黑树的插入底层【C++】_第2张图片
所以红黑树从根到叶子的最长可能路径不会超过最短可能路径的两倍,最多相等

红黑树结点

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

	}
	RBTreeNode<K,V>* _left;
	RBTreeNode<K, V>* _right;
	RBTreeNode<K, V>* _parent;
	pair<K, V> _kv;//键对值
	Colour _col;//颜色
};

为什么插入结点时,默认将结点的颜色设置为红色?

如果设置为黑色,插入路径上黑色结点的数目就比其他路径上黑色结点的数目就会多了一个,破坏了红黑树的性质4,此时我们就需要对红黑树进行调整。

设置为红色,此时如果其父结点也是红色的,就出现了连续的红色结点,破坏了红黑树的性质3,此时对红黑树进行调整;但如果其父结点是黑色的,那我们就无需对红黑树进行调整

插入黑色结点,一定破坏红黑树的性质4,必须进行调整。
插入红色结点,可能破坏红黑树的性质3,可能进行调整。
所以设置为红色

Insert

1、找到待插入位置。
2、将待插入结点插入到树中。
3、若插入结点的父结点是红色的,则需要对红黑树进行调整。

插入结点后不一定会进行调整,如果插入结点的父结点是黑色的,没有破坏红黑树的五点性质,就不用调整

如果插入结点的父结点是红色的,那么此时就出现了连续的红色结点,破坏红黑树的性质,就要调整

插入结点的父结点是红色的,还说明父结点不是根结点(因为根结点是黑色的),所以插入结点的祖父结点(父结点的父结点)就一定存在

如何调整?

1、情况一:插入结点的叔叔存在,且叔叔的颜色是红色。
红黑树的插入底层【C++】_第3张图片
避免出现连续的红色结点,将父结点变黑,
为了保持每条路径黑色结点的数目不变,将祖父结点变红,再将叔叔变黑。

此时祖父结点变成了红色,
如果祖父结点是根结点,将祖父结点变成黑色即可,此时相当于每条路径黑色结点的数目都增加了一个

如果祖父结点不是根结点,继续向上更新(将祖父结点当作新插入的结点,再判断其父结点是否为红色,若其父结点也是红色,那么又需要根据其叔叔的不同,进而进行不同的调整操作)

抽象图表示如下:
红黑树的插入底层【C++】_第4张图片

2、情况二:插入结点的叔叔存在,且叔叔的颜色是黑色。
红黑树的插入底层【C++】_第5张图片

注意:
从根结点一直走到空位置就算一条路径,并不是从根结点走到左右结点均为空的叶子结点时才算一条路径
uncle不存在和uncle存在且为黑色这两种情况需要旋转 ,旋转处理后不需要继续往上进行调整,所以说情况二一定是由情况一往上调整的过程中出现的

如何旋转?
cur、parent、grandfather这三个结点为一条直线,就单旋,再进行颜色调整

红黑树的插入底层【C++】_第6张图片
当直线关系为,parent是grandfather的右孩子,cur是parent的右孩子时,就需要先进行左单旋操作,再进行颜色调整

cur、parent、grandfather这三个结点为一条折线
进行双旋操作,再进行颜色调整,颜色调整后这棵被旋转子树的根是黑色

红黑树的插入底层【C++】_第7张图片
折线关系为,parent是grandfather的右孩子,cur是parent的左孩子时,就需要先进行右左双旋操作,再进行颜色调整

3、情况三:插入结点的叔叔不存在。
结论:cur结点一定是新插入的结点,不可能是由情况一变化而来的
因为叔叔不存在说明在parent的下面不可能再挂黑色结点了

红黑树的插入底层【C++】_第8张图片

如果插入前parent的右孩子是黑色结点,就会导致两条路径黑色结点的数目不相同,
parent是红色的,因此parent的右孩子不能是红色节点,从而得出结论:cur结点一定是新插入的结点

如何旋转?
cur、parent、grandfather这三个结点为一条直线,则我们需要先进行单旋操作,再进行颜色调整,颜色调整后这棵被旋转子树的根结点是黑色的,无需继续往上进行处理

直线关系为,parent是grandfather的右孩子,cur是parent的右孩子时,就需要先进行左单旋操作,再进行颜色调整
红黑树的插入底层【C++】_第9张图片
cur、parent、grandfather这三个结点为一条折线
红黑树的插入底层【C++】_第10张图片

parent是grandfather的右孩子,cur是parent的左孩子时,就需要先进行右左双旋操作,再进行颜色调整

	bool 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 != nullptr)
		{
			if (cur->_kv.first > kv.first)
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (cur->_kv.first < kv.first)
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				return false;
			}
		}


		cur = new Node(kv);
		cur->_col = RED;
		//将插入节点插入到树中 
		if (parent->_kv.first > kv.first)
		{
			parent->_left = cur;
		}
		else//parent->_kv.first < kv.first
		{
			parent->_right = cur;
		}
		cur->_parent = parent;

		//如果插入节点的父节点是红色,分三种情况进行调整 
		while (parent!=nullptr &&parent->_col == RED)
		{
			Node* grandfather = parent->_parent;



			if (parent == grandfather->_left)
			{
				Node* uncle = grandfather->_right;
				//插入结点的叔叔存在,且颜色是红色
				if (uncle != nullptr && uncle->_col == RED)
				{


					//parent 、uncle  变黑
					//grandfather变红
					parent->_col = BLACK;
					uncle->_col = BLACK;
					grandfather->_col = RED;

					//向上处理 
					cur = grandfather;
					parent = cur->_parent;
				}
				//插入结点的叔叔存在,且颜色是黑色
				//插入节点的叔叔不存在
				//这两种情况统一处理
				else  if (uncle != nullptr && uncle->_col == BLACK || uncle == nullptr)
				{
					//先旋转再变色

					if (cur == parent->_left)
					{
						RotateR(grandfather);
						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					else//cur == parent->_right 
					{
						RotateL(parent);
						RotateR(grandfather);

						cur->_col = BLACK;
						grandfather->_col = RED;
					}

					break;
				}

				else
				{
					assert(false);
				}

			}
			else//parent == grandfather->_right
			{
				Node* uncle = grandfather->_left;
				//插入结点的叔叔存在,且颜色是红色
				if (uncle != nullptr && uncle->_col == RED)
				{


					//parent 、uncle  变黑
					//grandfather变红
					parent->_col = BLACK;
					uncle->_col = BLACK;
					grandfather->_col = RED;

					//向上处理 
					cur = grandfather;
					parent = cur->_parent;
				}
				//插入结点的叔叔存在,且颜色是黑色
				//插入节点的叔叔不存在
				//这两种情况统一处理
				else  if (uncle != nullptr && uncle->_col == BLACK || uncle == nullptr)
				{
					//先旋转再变色

					if (cur == parent->_left)
					{
						//双旋	
						RotateR(grandfather);
						RotateL(parent);


						cur->_col = BLACK;
						grandfather->_col = RED;
					}
					else//cur == parent->_right 
					{
						RotateL(grandfather);
						parent->_col = BLACK;
						grandfather->_col = RED;
					}

					break;
				}

				else
				{
					assert(false);
				}
			}
		}



		_root->_col = BLACK;
		return true;
	}
	void RotateL(Node* parent)
	{
		_rotateCount++;
		Node* cur = parent->_right;
		Node* curleft = cur->_left;

		// 1 和 3 链接
		parent->_right = curleft;
		if (curleft != nullptr)
		{
			//1和2链接 
			curleft->_parent = parent;
		}
		cur->_left = parent;

		parent->_parent = cur;


		Node* ppnode = parent->_parent;
		//parent 是根节点
		if (parent == _root)
		{
			cur->_parent = nullptr;
			_root = cur;
		}
		else//parent 是一个子树 
		{
			//parent是一个左子树

			if (ppnode->_left == parent)
			{
				//3和ppnode链接
				ppnode->_left = cur;
				cur->_parent = ppnode;
			}
			//parent是一个右子树
			else
			{
				//3和ppnode链接
				ppnode->_right = cur;
				cur->_parent = ppnode;
			}
		}

	}
	void RotateR(Node* parent)
	{
		_rotateCount++;
		Node* cur = parent->_left;
		Node* curright = cur->_right;

		//cur和parent 链接 

		cur->_right = parent;
		parent->_parent = cur;

		//curright和parent链接 
		parent->_left = curright;
		if (curright != nullptr)
		{
			curright->_parent = parent;
		}



		Node* ppnode = parent->_parent;
		if (parent == _root)//parent是根节点
		{
			cur->_parent = nullptr;
			_root = cur;//更新根节点
		}
		else//parent一个子树 
		{
			//parent是左子树 
			if (ppnode->_left == parent)
			{
				ppnode->_left = cur;
				cur->_parent = ppnode;
			}
			else//(ppnode->_right == parent)
				//parent是右子树 
			{
				ppnode->_right = cur;
				cur->_parent = ppnode;
			}
		}


	}

CheckColour

	bool CheckColour(Node* root, int blacknum, int benchMark)
	{
		if (root == nullptr)
		{
			if (blacknum != benchMark)
			{
				return  false;
			}
			return false;
		}
		else if (root->_col == BLACK)
		{
			blacknum++;

		}
		else 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);
	}

IsBalance

	bool IsBalance()
	{
	  return 	_IsBalance(_root);
	}

	bool _IsBalance(Node* root)
	{
		if (root == nullptr)
		{
			return  true;
		}
		//根节点必须是黑色
		if (root->_col != BLACK)
		{
			return false;
		}
		//基准值
		int benchMark = 0;
		Node* cur = _root;
		while (cur != nullptr)
		{
			if (cur->_col == BLACK)
			{
				benchMark++;
			}
			cur = cur->_left;
		}
		return CheckColour(root, 0, benchMark);
	}

完整代码

#pragma once 
#include
#include
#include
using namespace std;
enum Colour
{
	RED,
	BLACK
};

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

	}
	RBTreeNode<K, V>* _left;
	RBTreeNode<K, V>* _right;
	RBTreeNode<K, V>* _parent;
	pair<K, V> _kv;//键对值
	Colour _col;//颜色


};

template <class K, class V>
struct 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* cur = _root;
		Node* parent = nullptr;
		while (cur != nullptr)
		{
			if (cur->_kv.first > kv.first)
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (cur->_kv.first < kv.first)
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				return false;
			}
		}


		cur = new Node(kv);
		cur->_col = RED;
		//将插入节点插入到树中 
		if (parent->_kv.first > kv.first)
		{
			parent->_left = cur;
		}
		else//parent->_kv.first < kv.first
		{
			parent->_right = cur;
		}
		cur->_parent = parent;

		//如果插入节点的父节点是红色,分三种情况进行调整 
		while (parent!=nullptr &&parent->_col == RED)
		{
			Node* grandfather = parent->_parent;



			if (parent == grandfather->_left)
			{
				Node* uncle = grandfather->_right;
				//插入结点的叔叔存在,且颜色是红色
				if (uncle != nullptr && uncle->_col == RED)
				{


					//parent 、uncle  变黑
					//grandfather变红
					parent->_col = BLACK;
					uncle->_col = BLACK;
					grandfather->_col = RED;

					//向上处理 
					cur = grandfather;
					parent = cur->_parent;
				}
				//插入结点的叔叔存在,且颜色是黑色
				//插入节点的叔叔不存在
				//这两种情况统一处理
				else  if (uncle != nullptr && uncle->_col == BLACK || uncle == nullptr)
				{
					//先旋转再变色

					if (cur == parent->_left)
					{
						RotateR(grandfather);
						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					else//cur == parent->_right 
					{
						RotateL(parent);
						RotateR(grandfather);

						cur->_col = BLACK;
						grandfather->_col = RED;
					}

					break;
				}

				else
				{
					assert(false);
				}

			}
			else//parent == grandfather->_right
			{
				Node* uncle = grandfather->_left;
				//插入结点的叔叔存在,且颜色是红色
				if (uncle != nullptr && uncle->_col == RED)
				{


					//parent 、uncle  变黑
					//grandfather变红
					parent->_col = BLACK;
					uncle->_col = BLACK;
					grandfather->_col = RED;

					//向上处理 
					cur = grandfather;
					parent = cur->_parent;
				}
				//插入结点的叔叔存在,且颜色是黑色
				//插入节点的叔叔不存在
				//这两种情况统一处理
				else  if (uncle != nullptr && uncle->_col == BLACK || uncle == nullptr)
				{
					//先旋转再变色

					if (cur == parent->_left)
					{
						//双旋	
						RotateR(grandfather);
						RotateL(parent);


						cur->_col = BLACK;
						grandfather->_col = RED;
					}
					else//cur == parent->_right 
					{
						RotateL(grandfather);
						parent->_col = BLACK;
						grandfather->_col = RED;
					}

					break;
				}

				else
				{
					assert(false);
				}
			}
		}



		_root->_col = BLACK;
		return true;
	}
	void RotateL(Node* parent)
	{
		_rotateCount++;
		Node* cur = parent->_right;
		Node* curleft = cur->_left;

		// 1 和 3 链接
		parent->_right = curleft;
		if (curleft != nullptr)
		{
			//1和2链接 
			curleft->_parent = parent;
		}
		cur->_left = parent;

		parent->_parent = cur;


		Node* ppnode = parent->_parent;
		//parent 是根节点
		if (parent == _root)
		{
			cur->_parent = nullptr;
			_root = cur;
		}
		else//parent 是一个子树 
		{
			//parent是一个左子树

			if (ppnode->_left == parent)
			{
				//3和ppnode链接
				ppnode->_left = cur;
				cur->_parent = ppnode;
			}
			//parent是一个右子树
			else
			{
				//3和ppnode链接
				ppnode->_right = cur;
				cur->_parent = ppnode;
			}
		}

	}
	void RotateR(Node* parent)
	{
		_rotateCount++;
		Node* cur = parent->_left;
		Node* curright = cur->_right;

		//cur和parent 链接 

		cur->_right = parent;
		parent->_parent = cur;

		//curright和parent链接 
		parent->_left = curright;
		if (curright != nullptr)
		{
			curright->_parent = parent;
		}



		Node* ppnode = parent->_parent;
		if (parent == _root)//parent是根节点
		{
			cur->_parent = nullptr;
			_root = cur;//更新根节点
		}
		else//parent一个子树 
		{
			//parent是左子树 
			if (ppnode->_left == parent)
			{
				ppnode->_left = cur;
				cur->_parent = ppnode;
			}
			else//(ppnode->_right == parent)
				//parent是右子树 
			{
				ppnode->_right = cur;
				cur->_parent = ppnode;
			}
		}


	}
	bool CheckColour(Node* root, int blacknum, int benchMark)
	{
		if (root == nullptr)
		{
			if (blacknum != benchMark)
			{
				return  false;
			}
			return false;
		}
		else if (root->_col == BLACK)
		{
			blacknum++;

		}
		else 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 IsBalance()
	{
	  return 	_IsBalance(_root);
	}

	bool _IsBalance(Node* root)
	{
		if (root == nullptr)
		{
			return  true;
		}
		//根节点必须是黑色
		if (root->_col != BLACK)
		{
			return false;
		}
		//基准值
		int benchMark = 0;
		Node* cur = _root;
		while (cur != nullptr)
		{
			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;
};

你可能感兴趣的:(c++,开发语言)