RB-tree(红黑树)详解

RB-tree(红黑树)

红黑树的规则如下:

1.每个节点不是红色就是黑色

2.根节点为黑色

3.如果节点为红色,那么它的子节点必须为黑色

4.任何一个节点到NULL(树的尾端)的任何路径所包含的黑节点个数相同

简而言之就是每个路径的黑色节点数量相同

新增的节点必须为红,因为增加红色节点所要付出的代价会比黑色的要小很多,如果新增节点为黑色,那么就会打破第四条规则,整棵树都要调整,代价是相当之大的

红黑树节点的定义

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;
	Colour _col;

	RBTreeNode()
		:_left(nullptr)
		,_right(nullptr)
		,_parent(nullptr)
		,_kv(kv)
	{
    
    }
};

红黑树的插入操作

红黑树的插入操作分为几种情况

情况一:

当cur为红、parent为红、grandparent为黑、uncle存在并且为红

操作过程:

将parent和uncle全部染成黑色,grandparent染成红色,然后把cur给grandparent继续向上判断,如果cur的parent依旧为红色,那么就要继续染色,如果cur为_root了,将根节点染成黑色。

具象图:

抽象图:

在抽象图当中,在a或者b子树当中触发了染色机制,然后一路染色上来,一直到cur也染成了红色,cur和p就造成冲突,需要继续染色。

情况二:

当cur为红,p为红,g黑,u不存在/u为黑

操作:

p为g的左孩子,cur为p的左孩子,则进行右单旋转;

相反,p为g的右孩子,cur为p的右孩子,则进行左单旋转

最后p变为黑色,cur和g变为红色

具象图:

当uncle为空的时候

抽象图:

情况三:

当cur和p为红,g为黑,u为黑/不存在

如果parent为grandparent的左儿子,对parent左旋,再对grandparent右旋

如果parent为grandparent的右儿子,对parent右旋,再对grandparent左旋

cur染为黑色,cur和grandparent染为红色。

具象图:

抽象图:

红黑树+测试代码

#pragma once
#include"AVLTree.h"

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;
	Colour _col;

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


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* grandparent = parent->_parent;
			assert(grandparent);
			assert(grandparent->_col == Black);//父亲为红色,那么祖父一定为黑色,不然之前的插入就存在问题
			
			if (parent == grandparent->_left)
			{
    
    
				Node* uncle = grandparent->_right;
				//情况一,uncle存在并且uncle为红色,就要继续往上染色
				if (uncle && uncle->_col == Red)
				{
    
    
					parent->_col = uncle->_col = Black;
					grandparent->_col = Red;
					cur = grandparent;
					parent = cur->_parent;
				}
				else
				{
    
    
					//uncle不存在或者uncle为黑色就会走到这里
					//情况二+情况三
					if (cur == parent->_left)
					{
    
    
						// 情况二:右单旋+变色
						//     g 
						//   p   u
						// c
						//右旋+染色
						
						RotateR(grandparent);
						parent->_col = Black;
						grandparent->_col = Red;
					}
					else
					{
    
    
						// 情况三:左右单旋+变色
						//     g 
						//   p   u
						//     c
						RotateL(parent);
						RotateR(grandparent);
						cur->_col = Black;
						parent->_col = grandparent->_col = Red;
					}
					break;
				}
			}
			else
			{
    
    
				Node* uncle = grandparent->_left;
				if (uncle && uncle->_col == Red)
				{
    
    
					parent->_col = uncle->_col = Black;
					grandparent->_col = Red;
					cur = grandparent;
					parent = cur->_parent;
				}
				else
				{
    
    
					if (cur == parent->_right)
					{
    
    
						RotateL(grandparent);
						parent->_col = Black;
						grandparent->_col = Red;
					}
					else
					{
    
    
						RotateR(parent);
						RotateL(grandparent);
						cur->_col = Black;
						grandparent->_col = Red;
					}
					break;
				}
			}
		}
		_root->_col = Black;
		return true;
	}

	void InOrder()
	{
    
    
		_InOrder(_root);
		cout << endl;
	}

	bool IsBalance()
	{
    
    
		if (_root == nullptr)
		{
    
    
			return true;
		}

		if (_root->_col == Red)
		{
    
    
			cout << "根节点不是黑色" << endl;
			return false;
		}

		// 黑色节点数量基准值
		int benchmark = 0;
		Node* cur = _root;

		while (cur)
		{
    
    
		if (cur->_col == Black)
		++benchmark;

		cur = cur->_left;
		}

		return PrevCheck(_root, 0, benchmark);
	}

private:

	bool PrevCheck(Node* root, int blackNum, int& benchmark)
	{
    
    
		if (root == nullptr)
		{
    
    
			if (blackNum != benchmark)
			{
    
    
				cout << "某条黑色节点的数量不相等" << endl;
				return false;
			}
			else
			{
    
    
				return true;
			}
		}
		if (root->_col == Black)
		{
    
    
			++blackNum;
		}

		if (root->_col == Red && root->_parent->_col == Red)
		{
    
    
			cout << "存在连续的红色节点" << endl;
			return false;
		}
		return PrevCheck(root->_left, blackNum, benchmark)
			&& PrevCheck(root->_right, blackNum, benchmark);
	}


	void _InOrder(Node* root)
	{
    
    
		if (root == nullptr)
		{
    
    
			return;
		}

		_InOrder(root->_left);
		cout << root->_kv.first << ":" << root->_kv.second << endl;
		_InOrder(root->_right);
	}

	void RotateL(Node* parent)
	{
    
    
		Node* subR = parent->_right;
		Node* subRL = subR->_left;
		Node* pparent = parent->_parent;

		parent->_right = subRL;

		if (subRL)
		{
    
    
			subRL->_parent = parent;
		}

		subR->_left = parent;
		parent->_parent = subR;

		if (parent == _root)
		{
    
    
			_root = subR;
			subR->_parent = nullptr;
		}
		else
		{
    
    
			if (pparent->_left == parent)
			{
    
    
				pparent->_left = subR;
			}
			else
			{
    
    
				pparent->_right = subR;;
			}
			subR->_parent = pparent;
		}
	}

	void RotateR(Node* parent)
	{
    
    
		Node* subL = parent->_left;
		Node* subLR = subL->_right;

		parent->_left = subLR;

		Node* pparent = parent->_parent;

		//防止空指针
		if (subLR)
		{
    
    
			subLR->_parent = parent;
		}

		subL->_right = parent;
		parent->_parent = subL;

		if (parent == _root)
		{
    
    
			//如果parent就是根节点
			_root = subL;
			subL->_parent = nullptr;
		}
		else
		{
    
    
			//如果parent只是一颗子树的根节点,就还需要连接好parent
			//判断是左还是右节点
			if (pparent->_left == parent)
			{
    
    
				pparent->_left = subL;
			}
			else
			{
    
    
				pparent->_right = subL;
			}
			subL->_parent = pparent;
		}
	}

	Node* _root = nullptr;
};

void TestRBTree2()
{
    
    
	size_t N = 1000;
	srand(time(0));
	RBTree<int, int> t1;
	for (size_t i = 0; i < N; ++i)
	{
    
    
		int x = rand();
		cout << "Insert:" << x << ":" << i << endl;
		t1.Insert(make_pair(x, i));
	}
	cout << "IsBalance:" << t1.IsBalance() << endl;
}

运行结果:

猜你喜欢

转载自blog.csdn.net/AkieMo/article/details/131905842
今日推荐