红黑树的性质与实现

红黑树概念与特性

红黑树是一种自平衡二叉树,同时也是set和map的底层实现容器。

  1. 节点只能是黑或者红
  2. 根节点与叶子节点必须是黑色(这里的叶子节点指nullptr)
  3. 不能出现连续的红色节点
  4. 任意节点到其叶子节点的每一条路径上黑色节点数量必须相同

 单个节点的定义:


	template<class T>
	struct RBTreeNode
	{
		RBTreeNode<T>* _pLeft;//左孩子(指向左节点)
		RBTreeNode<T>* _pRight;//右孩子(指向右节点)
		RBTreeNode<T>* _pParent;//父节点(指向上一个节点)
		T _data;//存储的数据
		Colour _col;//当前节点的颜色

        //构造函数
		RBTreeNode(const T& data = T())
			:_pLeft(nullptr)
			, _pRight(nullptr)
			, _pParent(nullptr)
			, _data(data)
			, _col(RED)
		{
		}
	};

普通红黑树: 

 带哨兵位红黑树:

  1.  带哨兵位的红黑树,其哨兵位的 parent 指向根节点(64),同样的根节点的parent也指向哨兵位。
  2. 哨兵位的 left 指向最左节点(即指向最小值)
  3. 哨兵位的 right 指向最右节点(即指向最大值)

插入节点的实现

首先我们会面临第一个问题,插入的节点应该是什么颜色的?

答:插入节点应为红色。因为树本身原来是平衡的,插入黑色节点一定会违反规则4(任意节点到其叶子节点的每一条路径上黑色节点数量必须相同),插入红色则是可能会违反规则3(不能出现连续的红色节点)对比之下,显然新节点设置为红色更合理。

调整平衡

注:在此处树为空时,头节点所有指针指向自己。

根据   左子树的值   <   根的值   <   右子树的值   找到合适的插入位置(即cur)后,可能有以下情况。

情况一

这种情况只需要将p节点和u节点变成黑色,并且将g节点变成红色就可以了。

  • (1)首先,因为节点位置没有改变,数值大小符合二叉树原则
  • (2)其次,同一条路径上黑色节点数量没有改变(为什么没有改变?从g开始往下走,虽然g节点改为红导致黑色节点减一,但是g节点的左右子树黑色节点各自加一,所以总径上的黑色节点总数没变)

 

 注意:因为g节点可能会是根节点,如果是最后要重新变为黑色(规则2根节点和叶子节点必须是黑色的)。

情况二

如果叔叔节点不存在,则参考左图,如果存在且为黑参考右图(绿色框框代表一棵子树)。

为什么要这么画?因为如果叔叔节点存在且为黑,那么用图一表示时树已经失衡了(右边路径的黑色节点数已经为2,而左边仅为1)。图二的三棵子树保证了每条路径都有相同的黑色节点数。不存在插入就出现左图并且叔叔存在且为黑的情况,因为插入前红黑树已经失衡。而右图的情况会在向上调整中出现。

情况二处理起来要麻烦的多,当p为g的左孩子,且cur为p的左孩子,则进行右单旋。

当p为g的左孩子,且cur为p的右孩子,则先以p节点旋转点进行左单旋,再以g节点为旋转点进行右单旋。

向上调整

当调整后要检查当前的g节点是否为红色,如果是,则可能出现连续红色节点需要将g赋值给c重新进行调整。

插入实现逻辑及代码

pair<iterator, bool> Insert(const T& data)
		{
            //判断根节点是否为空
            //为空则生成节点并建立连接
			if (_pHead->_pParent == _pHead)
			{
				Node* _root = new Node(data);
				_root->_col = BLACK;
				_pHead->_pParent = _root;
				_pHead->_pLeft = _root;
				_pHead->_pRight = _root;
				_root->_pParent = _pHead;
				return pair<iterator, bool>({ _root ,true });
			}
            
            //调用仿函数需要的对象
			KeyOfValue kot;

            //记录当前位置和上一个位置
			Node* parent = _pHead;
			Node* cur = _pHead->_pParent;

            //查找一个合适的插入节点的位置
			while (cur)
			{
				if (kot(data) > kot(cur->_data))
				{
					parent = cur;
					cur = cur->_pRight;
				}
				else if (kot(data) < kot(cur->_data))
				{
					parent = cur;
					cur = cur->_pLeft;
				}
				else
				{
					return pair<iterator, bool>({ nullptr ,false });
				}
			}
            
            //找到合适位置后生成节点
			cur = new Node(data);
            //ret记录返回节点,最后用于返回
			Node* ret = cur;

            //判断当前节点应该是父节点的左孩子还是右孩子,然后连接
			if (kot(parent->_data) < kot(data))
			{
				parent->_pRight = cur;
			}
			else
			{
				parent->_pLeft = cur;
			}
			cur->_pParent = parent;


			//调整平衡因子
			while (parent != _pHead && parent->_col == RED)
			{
				Node* grandfather = parent->_pParent;

				if (parent == grandfather->_pLeft)
				{
					Node* uncle = grandfather->_pRight;
					if (uncle && uncle->_col == RED)
					{
						grandfather->_col = RED;
						parent->_col = uncle->_col = BLACK;

						cur = grandfather;
						parent = cur->_pParent;
					}
					else//叔叔不存在或颜色为黑
					{
						if (cur == parent->_pLeft)
						{
							RotateR(grandfather);
							parent->_col = BLACK;
							grandfather->_col = RED;
						}
						else
						{
							RotateL(parent);
							RotateR(grandfather);
							cur->_col = BLACK;
							grandfather->_col = RED;
						}
						break;
					}
				}
				else
				{
					Node* uncle = grandfather->_pLeft;
					if (uncle && uncle->_col == RED)
					{
						parent->_col = uncle->_col = BLACK;
						grandfather->_col = RED;

						cur = grandfather;
						parent = cur->_pParent;
					}
					else//叔叔不存在或颜色为黑
					{
						if (cur == parent->_pRight)
						{
							RotateL(grandfather);
							parent->_col = BLACK;
							grandfather->_col = RED;
						}
						else
						{
							RotateR(parent);
							RotateL(grandfather);
							cur->_col = BLACK;
							grandfather->_col = RED;
						}
						break;
					}
				}
			}
            //将根节点颜色改为黑,并更新头节点指向的最左节点和最右节点
			_pHead->_pParent->_col = BLACK;
			_pHead->_pLeft = _LeftMost();
			_pHead->_pRight = _RightMost();
			return pair<iterator,bool>({ ret ,true });
		}

仿函数兼容数据类型

在插入函数中常常能看见if (kot(data) > kot(cur->_data))这样的代码,kot是为了调用仿函数的所创建的对象。

为了兼容pair类型和普通类型,在上层的set和map中实现了提取数据的仿函数。为什么做在set和map中?因为红黑树他无法知道是常规类型还是pair类型,但上层的set和map知道。

namespace MySet
{
	template<class K>
	class Set
	{
	public:
        //仿函数
		struct KOfV
		{
		public:
			const K& operator()(const K& k)
			{
				return k;
			}
		};

        typedef typename RB::RBTree<const K, KOfV>::iterator iterator;
    
        //以下函数都是对红黑树接口的复用
		iterator begin()
		{
			return _t.Begin();
		}

		iterator end()
		{
			return _t.End();
		}

		bool insert(const K& key)
		{
			return (_t.Insert(key)).second;
		}
	private:

		RB::RBTree<const K, KOfV> _t;
	};
}

 比较时是根据键值来判断大小的,所以仿函数返回kv.first。

namespace MyMap
{
	template<class K, class V>
	class Map
	{
	public:
        //仿函数
		struct KOfV
		{
		public:
			const K& operator()(const pair<K, V>& kv)
			{
				return kv.first;
			}
		};

		typedef typename RB::RBTree<pair<const K, V>, KOfV>::iterator iterator;
        

        //以下函数都是对红黑树接口的复用
		iterator begin()
		{
			return _t.Begin();
		}

		iterator end()
		{
			return _t.End();
		}

		bool insert(const pair<K, V>& kv)
		{
			return (_t.Insert(kv)).second;
		}

	private:
		RB::RBTree<pair<const K, V>, KOfV> _t;
	};
}

迭代器实现

主要是实现++和--的重载,按照从小到大的顺序遍历则恰好是中序遍历。所以最左节点是起点,最右节点是终点。而++与--最重要的逻辑是寻找下一个节点。

寻找++的下一个节点

方法

(1)若当前节点(cur)有右子树则进入右子树中寻找最左节点。

(2)若没有,则向上查找一个祖先节点,而cur必须位于该祖先节点的左子树否则继续向上查找。

原理

(1)因为是从小到大遍历,则++的下一个一定大于当前节点同时小于其余未遍历节点。要寻找这样的节点首先去右子树找右子树的最小节点(最左节点)。

(2)若不存在右子树,只能去找祖先节点,又因为搜索二叉树的特性(左子树值<根值<右子树值),必须找一个cur所在子树是该祖先节点的左子树。

 寻找--的下一个节点

方法

(1)若当前节点(cur)有左子树则进入左子树中寻找最右节点。

(2)若没有,则向上查找一个祖先节点,而cur必须位于该祖先节点的右子树否则继续向上查找。

原理

(1)因为是从大到小遍历,则--的下一个一定小于当前节点同时大于其余未遍历节点。要寻找这样的节点首先去左子树找左子树的最大节点(最右节点)。

(2)若不存在左子树,只能去找祖先节点,又因为搜索二叉树的特性(左子树值<根值<右子树值),必须找一个cur所在子树是该祖先节点的右子树。

template<class T, class Ref, class Ptr>
	struct RBTreeIterator
	{
		typedef RBTreeNode<T> Node;
		typedef RBTreeIterator<T, Ref, Ptr> Self;

		RBTreeIterator(Node* pNode)
			: _pNode(pNode)
		{}

		// 让迭代器具有类似指针的行为
		Ref operator*()
		{
			return _pNode->_data;
		}
		Ptr operator->()
		{
			return &_pNode->_data;
		}

		// 然迭代器可以移动:前置/后置++  
		Self& operator++()
		{
			if (_pNode->_pRight)
			{
				Node* RightMin = _pNode->_pRight;
				while (RightMin->_pLeft)
				{
					RightMin = RightMin->_pLeft;
				}
				_pNode = RightMin;
			}
			else
			{
				Node* cur = _pNode;
				Node* parent = cur->_pParent;
				while (parent && cur == parent->_pRight)
				{
					cur = parent;
					parent = cur->_pParent;
				}
				_pNode = parent;
			}
			return *this;
		}
		Self operator++(int)
		{
			Node* temp = _pNode;
			if (_pNode->_pRight)
			{
				Node* RightMin = _pNode->_pRight;
				while (RightMin->_pLeft)
				{
					RightMin = RightMin->_pLeft;
				}
				_pNode = RightMin;
			}
			else
			{
				Node* cur = _pNode;
				Node* parent = cur->_pParent;
				while (parent && cur == parent->_pRight)
				{
					cur = parent;
					parent = cur->_pParent;
				}
				_pNode = parent;
			}
			return temp;
		}
		// 然迭代器可以移动:前置/后置-- 
		Self& operator--()
		{
			if (_pNode->_pLeft)
			{
				Node* LeftMax = _pNode->_pLeft;
				while (LeftMax->_pRight)
				{
					LeftMax = LeftMax->_pRight;
				}
				_pNode = LeftMax;
			}
			else
			{
				Node* cur = _pNode;
				Node* parent = cur->_pParent;
				while (parent && cur == parent->_pLeft)
				{
					cur = parent;
					parent = cur->_pParent;
				}
				_pNode = parent;
			}
			return *this;
		}
		Self operator--(int)
		{
			Node* temp = _pNode;
			if (_pNode->_pLeft)
			{
				Node* LeftMax = _pNode->_pLeft;
				while (LeftMax->_pRight)
				{
					LeftMax = LeftMax->_pRight;
				}
				_pNode = LeftMax;
			}
			else
			{
				Node* cur = _pNode;
				Node* parent = cur->_pParent;
				while (parent && cur == parent->_pLeft)
				{
					cur = parent;
					parent = cur->_pParent;
				}
				_pNode = parent;
			}
			return temp;
		}

		// 让迭代器可以比较
		bool operator!=(const Self& s)const
		{
			return _pNode != s._pNode;
		}
		bool operator==(const Self& s)const
		{
			return _pNode == s._pNode;
		}

	private:
		Node* _pNode;
	};

完整代码实现

#pragma once
#pragma once
#include<assert.h>
#include<vector>
#include<iostream>
using namespace std;

namespace RB
{
	enum Colour
	{
		RED,
		BLACK
	};

	template<class T>
	struct RBTreeNode
	{
		RBTreeNode<T>* _pLeft;
		RBTreeNode<T>* _pRight;
		RBTreeNode<T>* _pParent;
		T _data;
		Colour _col;

		RBTreeNode(const T& data = T())
			:_pLeft(nullptr)
			, _pRight(nullptr)
			, _pParent(nullptr)
			, _data(data)
			, _col(RED)
		{
		}
	};

	template<class T, class Ref, class Ptr>
	struct RBTreeIterator
	{
		typedef RBTreeNode<T> Node;
		typedef RBTreeIterator<T, Ref, Ptr> Self;

		RBTreeIterator(Node* pNode)
			: _pNode(pNode)
		{}

		// 让迭代器具有类似指针的行为
		Ref operator*()
		{
			return _pNode->_data;
		}
		Ptr operator->()
		{
			return &_pNode->_data;
		}

		// 然迭代器可以移动:前置/后置++  
		Self& operator++()
		{
			if (_pNode->_pRight)
			{
				Node* LeftMin = _pNode->_pRight;
				while (LeftMin->_pLeft)
				{
					LeftMin = LeftMin->_pLeft;
				}
				_pNode = LeftMin;
			}
			else
			{
				Node* cur = _pNode;
				Node* parent = cur->_pParent;
				while (parent && cur == parent->_pRight)
				{
					cur = parent;
					parent = cur->_pParent;
				}
				_pNode = parent;
			}
			return *this;
		}
		Self operator++(int)
		{
			Node* temp = _pNode;
			if (_pNode->_pRight)
			{
				Node* RightMin = _pNode->_pRight;
				while (RightMin->_pLeft)
				{
					RightMin = RightMin->_pLeft;
				}
				_pNode = RightMin;
			}
			else
			{
				Node* cur = _pNode;
				Node* parent = cur->_pParent;
				while (parent && cur == parent->_pRight)
				{
					cur = parent;
					parent = cur->_pParent;
				}
				_pNode = parent;
			}
			return temp;
		}
		// 然迭代器可以移动:前置/后置-- 
		Self& operator--()
		{
			if (_pNode->_pLeft)
			{
				Node* LeftMax = _pNode->_pLeft;
				while (LeftMax->_pRight)
				{
					LeftMax = LeftMax->_pRight;
				}
				_pNode = LeftMax;
			}
			else
			{
				Node* cur = _pNode;
				Node* parent = cur->_pParent;
				while (parent && cur == parent->_pLeft)
				{
					cur = parent;
					parent = cur->_pParent;
				}
				_pNode = parent;
			}
			return *this;
		}
		Self operator--(int)
		{
			Node* temp = _pNode;
			if (_pNode->_pLeft)
			{
				Node* LeftMax = _pNode->_pLeft;
				while (LeftMax->_pRight)
				{
					LeftMax = LeftMax->_pRight;
				}
				_pNode = LeftMax;
			}
			else
			{
				Node* cur = _pNode;
				Node* parent = cur->_pParent;
				while (parent && cur == parent->_pLeft)
				{
					cur = parent;
					parent = cur->_pParent;
				}
				_pNode = parent;
			}
			return temp;
		}

		// 让迭代器可以比较
		bool operator!=(const Self& s)const
		{
			return _pNode != s._pNode;
		}
		bool operator==(const Self& s)const
		{
			return _pNode == s._pNode;
		}

	private:
		Node* _pNode;
	};

// T: 可能是键值对<key,value>
//    可能是一个key
// 不论节点中存储的是<key, value> || key, 都是按照key来进行比较的
// KeyOfValue: 提取data中的Key
	template<class T, class KeyOfValue>
	class RBTree
	{
		typedef RBTreeNode<T> Node;
	public:
		typedef RBTreeIterator<T, T&, T*> iterator;
	public:
		RBTree()
			: _size(0)
		{
			_pHead = new Node;
			_pHead->_pLeft = _pHead;
			_pHead->_pRight = _pHead;
			_pHead->_pParent = _pHead;
		}

		~RBTree()
		{
			_Destroy();
		}

		// 插入值为data的节点
		// 返回值含义:iterator代表新插入节点   bool:代表释放插入成功
		pair<iterator, bool> Insert(const T& data)
		{
			if (_pHead->_pParent == _pHead)
			{
				Node* _root = new Node(data);
				_root->_col = BLACK;
				_pHead->_pParent = _root;
				_pHead->_pLeft = _root;
				_pHead->_pRight = _root;
				_root->_pParent = _pHead;
				return pair<iterator, bool>({ _root ,true });
			}

			KeyOfValue kot;
			Node* parent = _pHead;
			Node* cur = _pHead->_pParent;

			while (cur)
			{
				if (kot(data) > kot(cur->_data))
				{
					parent = cur;
					cur = cur->_pRight;
				}
				else if (kot(data) < kot(cur->_data))
				{
					parent = cur;
					cur = cur->_pLeft;
				}
				else
				{
					return pair<iterator, bool>({ nullptr ,false });
				}
			}

			cur = new Node(data);
			Node* ret = cur;
			if (kot(parent->_data) < kot(data))
			{
				parent->_pRight = cur;
			}
			else
			{
				parent->_pLeft = cur;
			}
			cur->_pParent = parent;


			//调整平衡因子
			while (parent != _pHead && parent->_col == RED)
			{
				Node* grandfather = parent->_pParent;

				if (parent == grandfather->_pLeft)
				{
					Node* uncle = grandfather->_pRight;
					if (uncle && uncle->_col == RED)
					{
						grandfather->_col = RED;
						parent->_col = uncle->_col = BLACK;

						cur = grandfather;
						parent = cur->_pParent;
					}
					else//叔叔不存在或颜色为黑
					{
						if (cur == parent->_pLeft)
						{
							RotateR(grandfather);
							parent->_col = BLACK;
							grandfather->_col = RED;
						}
						else
						{
							RotateL(parent);
							RotateR(grandfather);
							cur->_col = BLACK;
							grandfather->_col = RED;
						}
						break;
					}
				}
				else
				{
					Node* uncle = grandfather->_pLeft;
					if (uncle && uncle->_col == RED)
					{
						parent->_col = uncle->_col = BLACK;
						grandfather->_col = RED;

						cur = grandfather;
						parent = cur->_pParent;
					}
					else//叔叔不存在或颜色为黑
					{
						if (cur == parent->_pRight)
						{
							RotateL(grandfather);
							parent->_col = BLACK;
							grandfather->_col = RED;
						}
						else
						{
							RotateR(parent);
							RotateL(grandfather);
							cur->_col = BLACK;
							grandfather->_col = RED;
						}
						break;
					}
				}
			}
			_pHead->_pParent->_col = BLACK;
			_pHead->_pLeft = _LeftMost();
			_pHead->_pRight = _RightMost();
			return pair<iterator,bool>({ ret ,true });
		}

		// Begin和End迭代器s
		iterator Begin()
		{
			return iterator(_pHead->_pLeft);
		}
		iterator End()
		{
			return iterator(_pHead);
		}


		void InOrder()
		{
			_InOrder(_pHead->_pParent);
		}
		
		// 检测红黑树是否为有效的红黑树,注意:其内部主要依靠_IsValidRBTRee函数检测
		bool IsValidRBTRee()
		{
			//根节点存在 && 根节点为红
			if (_pHead->_pParent != _pHead && _pHead->_pParent->_col == RED) return false;

			//一条路径的黑色节点个数
			int pathBlack = 0;
			Node* cur = _pHead->_pParent;
			while (cur)
			{
				if (cur->_col == BLACK)
					pathBlack++;
				cur = cur->_pLeft;
			}

			return _IsValidRBTRee(_pHead->_pParent, 0, pathBlack);
		}

		// 红黑树是否为红,是返回true,否则返回false
		bool Empty()const
		{
			return Size() == 0;
		}
		// 返回红黑树中有效节点的个数
		size_t Size()const
		{
			return _size;
		}
		// 将红黑树中的有效节点删除,注意:删除的是有效节点,不删除头结点
		void Clear()
		{
			if (_pHead->_pParent == _pHead) return;

			Node* cur = _pHead->_pParent;
			_Clear(cur);
		}

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

			_Clear(root->_pLeft);
			_Clear(root->_pRight);
			delete root;
		}

		// 在红黑树中查找data,存在赶回该节点对应的迭代器,否则返回End()
		iterator Find(const T& data)
		{
			KeyOfValue kot;
			Node* cur = _pHead->_pParent;
			while (cur)
			{
				if (kot(cur->_data) < kot(data))
				{
					cur = cur->_pRight;
				}
				else if (kot(cur->_data) > kot(data))
				{
					cur = cur->_pLeft;
				}
				else
				{
					return cur;
				}
			}

			return nullptr;
		}

	private:
		Node* _LeftMost()
		{
			if (_pHead->_pParent == _pHead) return nullptr;

			Node* cur = _pHead->_pParent;
			while (cur->_pLeft)
			{
				cur = cur->_pLeft;
			}

			return cur;
		}
		Node* _RightMost()
		{
			if (_pHead->_pParent == _pHead) return nullptr;

			Node* cur = _pHead->_pParent;
			while (cur->_pRight)
			{
				cur = cur->_pRight;
			}

			return cur;
		}

		void _Destroy()
		{
			Clear();
			delete _pHead;
		}

		void RotateL(Node* pParent)
		{
			{
				Node* subR = pParent->_pRight;
				Node* subRL = subR->_pLeft;

				pParent->_pRight = subRL;
				if (subRL)
					subRL->_pParent = pParent;
				subR->_pLeft = pParent;
				Node* temp = pParent->_pParent;
				pParent->_pParent = subR;

				//pParent有可能为根,右单旋后应该更新根节点指向。
				if (pParent == _pHead)
				{
					_pHead = subR;
					_pHead->_pParent = nullptr;
				}
				else
				{
					if (temp->_pLeft == pParent)
					{
						temp->_pLeft = subR;
					}
					else
					{
						temp->_pRight = subR;
					}
					subR->_pParent = temp;
				}
			}
		}
		void RotateR(Node* pParent)
		{
			{
				Node* subL = pParent->_pLeft;
				Node* subLR = subL->_pRight;

				pParent->_pLeft = subLR;
				if (subLR)
					subLR->_pParent = pParent;
				subL->_pRight = pParent;
				Node* temp = pParent->_pParent;
				pParent->_pParent = subL;

				//pParent有可能为根,右单旋后应该更新根节点指向。
				if (pParent == _pHead)
				{
					_pHead = subL;
					_pHead->_pParent = nullptr;
				}
				else
				{
					if (temp->_pLeft == pParent)
					{
						temp->_pLeft = subL;
					}
					else
					{
						temp->_pRight = subL;
					}
					subL->_pParent = temp;
				}
			}
		}

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

			_InOrder(root->_pLeft);
			cout << root->_data << endl;
			_InOrder(root->_pRight);
		}

		bool _IsValidRBTRee(Node* pRoot, size_t blackCount, size_t pathBlack)
		{
			if (pRoot == nullptr)
			{
				if (blackCount != pathBlack)
				{
					return false;
				}
				else
				{
					return true;
				}
			}

			if (pRoot->_col == RED && pRoot->_pParent->_col == RED)
			{
				return false;
			}

			if (pRoot->_col == BLACK)
			{
				blackCount++;
			}

			return _IsValidRBTRee(pRoot->_pLeft, blackCount, pathBlack)
				&& _IsValidRBTRee(pRoot->_pRight, blackCount, pathBlack);
		}

		Node*& GetRoot()
		{
			return _pHead->_pParent == _pHead ? nullptr : _pHead->_pParent;
		}

	private:
		Node* _pHead;
		size_t _size;
	};

}

  • 29
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值