C++ 红黑树

1. 红黑树的概念

红黑树 ,是一种 二叉搜索树 ,但 在每个结点上增加一个存储位表示结点的颜色,可以是 Red
Black 。 通过对 任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路
径会比其他路径长出俩倍 ,因而是 接近平衡 的。
红黑树的性质
1. 每个结点不是红色就是黑色
2. 根节点是黑色的 
3. 如果一个节点是红色的,则它的两个孩子结点是黑色的 
4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点 
5. 每个叶子结点都是黑色的 ( 此处的叶子结点指的是空结点 )

2. 红黑树节点的定义

enum Color
	{
		RED,
		BLACK,
	};
	template <class T>
	struct RBTreeNode
	{
		//构造函数
		RBTreeNode(T data)
			:_left(nullptr)
			,_right(nullptr)
			,_parent(nullptr)
			,_data(data)
			,_col(RED)
		{}
		//成员变量
		RBTreeNode* _left;
		RBTreeNode* _right;
		RBTreeNode* _parent;
		T _data;//节点数据
		Color _col;//颜色
    };

3.红黑树的构造函数

4. 红黑树的插入

如果我们要插入的结点的父亲节点为红色,我们就会出现连续的红色节点,这时我们就需要进行调整了。

uncle为红色节点

uncle节点为红色,此时需要进行变色

由于新插入了红色的cur节点,此时parent与cur出现了连续的红色节点,于是我们将parent改为黑色。但是此时以parent为根的所有路径就会多出一个黑节点,于是把grandfather变为红色,来抵消这个新增的黑节点。但是此时以uncle为根的路径又会少一个黑节点,于是把uncle变黑。

但是我们将grandfather变为了红色,这有可能会影响到上一层节点,比如这样:

我们把grandfather变红之后,又出现了两个红色节点相连的情况,所以我们要写一个while循环,来反复向上检查。

uncle为空或者黑色节点

单旋

进行单旋,会把c树交给grandfather做子树,而c与uncle为根的路径黑节点数目相同,不违背规则旋转后,parent作新根,grandfather与cur作为左右子树grandfather为根的路径,整体上就会比以cur为根的路径多出一个黑节点(即grandfather本身),因此,将grandfather改为红节点,来平衡parent左右子树的黑节点,而红色节点不能连续出现,再把parent改为黑节点。

//左单旋
void RotateL(Node* parent)
{
	Node* subR = parent->_right;
	Node* subRL = subR->_left;
	Node* grandparent = parent->_parent;
	parent->_right = subRL;
	if (subRL)
	{
		subRL->_parent = parent;
	}
	subR->_left = parent;
	parent->_parent = subR;
	if (parent == _root)
	{
		_root = subR;
	}
	else
	{
		if (grandparent->_left == parent)
			grandparent->_left = subR;
		else
			grandparent->_right = subR;
	}
	subR->_parent = grandparent;
}
//右单旋
void RotateR(Node* parent)
{
	Node* subL = parent->_left;
	Node* subLR = subL->_right;
	Node* grandparent = parent->_parent;
	parent->_left = subLR;
	if (subLR)
	{
		subLR->_parent = parent;
	}
	subL->_right = parent;
	parent->_parent = subL;
	if (parent == _root)
	{
		_root = subL;
	}
	else
	{
		if (grandparent->_left == parent)
			grandparent->_left = subL;
		else
			grandparent->_right = subL;
	}
	subL->_parent = grandparent;
}

双旋

进行双旋,会把C子树交给grandfather做子树,而C与uncle黑节点数目相同,不违背规则;也会把B交给parent做子树,A与B黑节点数目相同,不违背规则;旋转后,cur作新根,grandfather与parent作为左右子树grandfather为根的路径,整体上就会比以parent为根的路径多出一个黑节点(grandfather本身)因此,将grandfather改为红节点,来平衡cur左右子树的黑节点而红色节点不能连续出现,再把cur改为黑节点以上单旋和双旋的变色,看似复杂,其实最后都是把新根的颜色变为黑色,新根的左右子树变为红色。由于我们旋转后,新根都是黑节点,所以不会影响上层,可以直接跳出循环。

//左右双旋
void RotateLR(Node* parent)
{
	Node* subL = parent->_left;
	Node* subLR = subL->_right;
	RotateL(subL);
	RotateR(parent);
}
//右左双旋
void RotateRL(Node* parent)
{
	Node* subR = parent->_right;
	Node* subRL = parent->_left;
	RotateR(subR);
	RotateL(parent);
}

插入的完整代码

pair<iterator, bool> Insert(const T& data)
{
	KeyOfT kot;
	//第一次插入
	if (_root == nullptr)
	{
		_root = new Node(data);
		_root->_col = BLACK;
		return make_pair(iterator(_root), true);
	}
	//找位置插入
	Node* cur = _root, * parent = _root;
	while (cur)
	{
		if (kot(data) < kot(cur->_data))
		{
			parent = cur;
			cur = cur->_left;
		}
		else if (kot(data) > kot(cur->_data))
		{
			parent = cur;
			cur = cur->_right;
		}
		else
		{
			//该数据已经存在
			return make_pair(iterator(cur), false);
		}
	}
	//插入数据
	cur = new Node(data);
	cur->_parent = parent;
	if (kot(data) < kot(cur->_data))
		parent->_left = cur;
	else
		parent->_right = cur;
	Node* ret = cur;
	//检查颜色(当连续出现两个红色时需要调整)
	while (parent && parent->_col == RED)
	{
		Node* grandparent = parent->_parent;
		if (parent == grandparent->_left)
		{
			Node* uncle = grandparent->_right;
			//如果uncle存在且为红,则将parent和uncle变黑,grandparent变红
			if (uncle && uncle->_col == RED)
			{
				parent->_col = uncle->_col = BLACK;
				grandparent->_col = RED;
			}
			//uncle不存在或者为黑
			else
			{
				//将grandparent右旋,grandparent和cur变为红,parent变为黑
				if (cur == parent->_left)
				{
					RotateR(grandparent);
					cur->_col = grandparent->_col = RED;
					parent->_col = BLACK;
				}
				//将parent左旋,grandparent右旋,将cur变为黑,parent和grandparent变为红
				else
				{
					RotateL(parent);
					RotateR(grandparent);
					parent->_col = grandparent->_col = RED;
					cur->_col = BLACK;
				}
				break;
			}
		}
		else
		{
			Node* uncle = grandparent->_left;
			//如果uncle存在且为红,则将parent和uncle变黑,grandparent变红
			if (uncle && uncle->_col == RED)
			{
				parent->_col = uncle->_col = BLACK;
				grandparent->_col = RED;
			}
			//uncle不存在或者为黑
			else
			{
				//将grandparent左旋,grandparent和cur变为红,parent变为黑
				if (cur == parent->_right)
				{
					RotateL(grandparent);
					cur->_col = grandparent->_col = RED;
					parent->_col = BLACK;
				}
				//将parent右旋,grandparent左旋,将cur变为黑,parent和grandparent变为红
				else
				{
					RotateR(parent);
					RotateL(grandparent);
					parent->_col = grandparent->_col = RED;
					cur->_col = BLACK;
				}
				break;
			}
		}
	}
	//把根节点变为黑
	_root->_col = BLACK;
	return make_pair(iterator(ret), true);
}

5. 红黑树的迭代器

operator++

当迭代器指向哪一个节点,说明当前就遍历到了哪一个节点,此时迭代器处于这个蓝色框中的节点,说明这个节点的左子树已经遍历完了,刚好遍历到这个蓝色框节点。因此下一步就是中序遍历右子树,即让迭代器走到当前节点的右子树位置,并且找到右子树的最左节点,该节点就是下一个节点。

如果右子树为空,说明整颗子树都遍历完毕了,那么我们就要向上移动,走到当前节点的父节点处:

但是对于这个父节点而言,其左子树遍历完了,刚刚右子树遍历完毕后,走到了当前节点,说明当前节点也遍历完毕了,此时还要向上移动,以此类推,直到走到第一个当前节点是父节点的左子树的情况。

1.如果迭代器当前节点的右子树不为空,遍历右子树(找到右子树的最左节点)
2.如果迭代器当前节点的右子树为空,向上找前一个节点是当前节点的左子树的节点

operator--

同理,只是相反的:

1.如果迭代器当前节点的左子树不为空,遍历左子树(找到左子树的最右节点)
2.如果迭代器当前节点的左子树为空,向上找前一个节点是当前节点的右子树的节点

迭代器的完整代码

//实现迭代器
template<class T, class Ref, class Ptr>
struct RBTreeIterator
{
	typedef RBTreeNode<T> Node;
	typedef RBTreeIterator<T, Ref, Ptr> Self;
	Node* _node;
	//构造函数
	RBTreeIterator(const Node* node)
		:_node(node)
	{}
	Ref operator*()
	{
		return _node->_data;
	}
	Ptr operator->()
	{
		return &(_node->_data);
	}
	bool operator==(const Self& s)const
	{
		return _node == s._node;
	}
	bool operator!=(const Self& s)const
	{
		return _node != s._node;
	}
	//前置++
	Self& operator++()
	{
		//如果右子树不为空,说明该树未取完,要取右子树的最左结点
		if (_node->_right)
		{
			Node* left = _node->_right;
			while (left->_left)
			{
				left = left->_left;
			}
			_node = left;
		}
		//右子树为空,说明该树已经取完,要回到cur为左孩子的parent
		else
		{
			Node* cur = _node, * parent = cur->_parent;
			while (parent && parent->_right == cur)
			{
				cur = parent;
				parent = cur->_parent;
			}
			_node = parent;
		}
		return *this;
	}
	//后置++
	Self operator++(int)
	{
		Self old = new Self(_node);
		//如果右子树不为空,说明该树未取完,要取右子树的最左结点
		if (_node->_right)
		{
			Node* left = _node->_right;
			while (left->_left)
			{
				left = left->_left;
			}
			_node = left;
		}
		//右子树为空,说明该树已经取完,要回到cur为左孩子的parent
		else
		{
			Node* cur = _node, * parent = cur->_parent;
			while (parent && parent->_right == cur)
			{
				cur = parent;
				parent = cur->_parent;
			}
			_node = parent;
		}
		return old;
	}
	//前置--
	Self& operator--()
	{
		//如果左子树不为空,说明该树未取完,要取左子树的最右结点
		if (_node->_left)
		{
			Node* right = _node->_left;
			while (right->_right)
			{
				right = right->_right;
			}
			_node = right;
		}
		//左子树为空,说明该树已经取完,要回到cur为右孩子的parent
		else
		{
			Node* cur = _node, * parent = cur->_parent;
			while (parent && parent->_left == cur)
			{
				cur = parent;
				parent = cur->_parent;
			}
			_node = parent;
		}
		return *this;
	}
	//后置--
	Self operator--(int)
	{
		Self old = new Self(_node);
		//如果左子树不为空,说明该树未取完,要取左子树的最右结点
		if (_node->_left)
		{
			Node* right = _node->_left;
			while (right->_right)
			{
				right = right->_right;
			}
			_node = right;
		}
		//左子树为空,说明该树已经取完,要回到cur为右孩子的parent
		else
		{
			Node* cur = _node, * parent = cur->_parent;
			while (parent && parent->_left == cur)
			{
				cur = parent;
				parent = cur->_parent;
			}
			_node = parent;
		}
		return old;
	}
};

6.红黑树的判定h

bool _IsRBTree(Node* root, int count, int blacknum)
{
	if (root == nullptr)
	{
		if (count != blacknum)
		{
			return false;
		}
		return true;
	}
	if (root->_col == BLACK)
		count++;

	return _IsRBTree(root->_left, count, blacknum) &&
		_IsRBTree(root->_right, count, blacknum);
}
bool IsRBTree()
{
	if (_root->_col == RED)
	{
		return false;
	}
	int blacknum = 0;
	Node* cur = _root;
	while (cur)
	{
		if (cur->_col == BLACK)
			blacknum++;
		cur = cur->_left;
	}
	return _IsRBTree(_root, 0, blacknum);
}

7.红黑树的完整代码

#include <iostream>
#include <vector>
using namespace std;
namespace lbk
{
	enum Color
	{
		RED,
		BLACK,
	};
	template <class T>
	struct RBTreeNode
	{
		//构造函数
		RBTreeNode(T data)
			:_left(nullptr)
			,_right(nullptr)
			,_parent(nullptr)
			,_data(data)
			,_col(RED)
		{}
		//成员变量
		RBTreeNode* _left;
		RBTreeNode* _right;
		RBTreeNode* _parent;
		T _data;//节点数据
		Color _col;//颜色
    };
	//实现迭代器
	template<class T,class Ref,class Ptr>
	struct RBTreeIterator
	{
		typedef RBTreeNode<T> Node;
		typedef RBTreeIterator<T, Ref, Ptr> Self;
		Node* _node;
		//构造函数
		RBTreeIterator(const Node* node)
			:_node(node)
		{}
		Ref operator*()
		{
			return _node->_data;
		}
		Ptr operator->()
		{
			return &(_node->_data);
		}
		bool operator==(const Self& s)const
		{
			return _node == s._node;
		}
		bool operator!=(const Self& s)const
		{
			return _node != s._node;
		}
		//前置++
		Self& operator++()
		{
			//如果右子树不为空,说明该树未取完,要取右子树的最左结点
			if (_node->_right)
			{
				Node* left = _node->_right;
				while (left->_left)
				{
					left = left->_left;
				}
				_node = left;
			}
			//右子树为空,说明该树已经取完,要回到cur为左孩子的parent
			else
			{
				Node* cur=_node,*parent = cur->_parent;
				while (parent && parent->_right==cur)
				{
					cur = parent;
					parent = cur->_parent;
				}
				_node = parent;
			}
			return *this;
		}
		//后置++
		Self operator++(int)
		{
			Self old = new Self(_node);
			//如果右子树不为空,说明该树未取完,要取右子树的最左结点
			if (_node->_right)
			{
				Node* left = _node->_right;
				while (left->_left)
				{
					left = left->_left;
				}
				_node = left;
			}
			//右子树为空,说明该树已经取完,要回到cur为左孩子的parent
			else
			{
				Node* cur = _node, * parent = cur->_parent;
				while (parent && parent->_right == cur)
				{
					cur = parent;
					parent = cur->_parent;
				}
				_node = parent;
			}
			return old;
		}
		//前置--
		Self& operator--()
		{
			Self old = new Self(_node);
			//如果左子树不为空,说明该树未取完,要取左子树的最右结点
			if (_node->_left)
			{
				Node* right = _node->_left;
				while (right->_right)
				{
					right = right->_right;
				}
				_node = right;
			}
			//左子树为空,说明该树已经取完,要回到cur为右孩子的parent
			else
			{
				Node* cur = _node, * parent = cur->_parent;
				while (parent && parent->_left == cur)
				{
					cur = parent;
					parent = cur->_parent;
				}
				_node = parent;
			}
			return *this;
		}
	    //后置--
    	Self operator--(int)
	    {
			//如果左子树不为空,说明该树未取完,要取左子树的最右结点
			if (_node->_left)
			{
				Node* right = _node->_left;
				while (right->_right)
				{
					right = right->_right;
				}
				_node = right;
			}
			//左子树为空,说明该树已经取完,要回到cur为右孩子的parent
			else
			{
				Node* cur = _node, * parent = cur->_parent;
				while (parent && parent->_left == cur)
				{
					cur = parent;
					parent = cur->_parent;
				}
				_node = parent;
			}
			return *this;
	    }
	};
	template<class K,class T,class KeyOfT>
	class RBTree
	{
		typedef RBTreeNode<T> Node;
		typedef RBTreeIterator<T, T&, T*> iterator;
	public:
		//构造函数
		RBTree()
			:_root(nullptr)
		{}
		//析构函数
		void Destroy(Node* root)
		{
			if (root == nullptr)
			{
				return;
			}
			Destroy(root->_left);
			Destroy(root->_right);
			delete root;
		}
		~RBTree()
		{
			Destroy(_root);
			_root = nullptr;
		}
		iterator begin()
		{
			Node* left = _root;
			while (left->_left)
			{
				left = left->_left;
			}
			return iterator(left);
		}
		iterator end()
		{
			return iterator(nullptr);
		}
		pair<iterator,bool> Insert(const T& data)
		{
			KeyOfT kot;
			//第一次插入
			if (_root == nullptr)
			{
				_root = new Node(data);
				_root->_col = BLACK;
				return make_pair(iterator(_root), true);
			}
			//找位置插入
			Node* cur = _root, * parent = _root;
			while (cur)
			{
				if (kot(data)< kot(cur->_data))
				{
					parent = cur;
					cur = cur->_left;
				}
				else if (kot(data) > kot(cur->_data))
				{
					parent = cur;
					cur = cur->_right;
				}
				else
				{
					//该数据已经存在
					return make_pair(iterator(cur), false);
				}
			}
			//插入数据
			cur = new Node(data);
			cur->_parent = parent;
			if (kot(data) < kot(cur->_data))
				parent->_left = cur;
			else
				parent->_right = cur;
			Node* ret = cur;
			//检查颜色(当连续出现两个红色时需要调整)
			while (parent&&parent->_col==RED)
			{
				Node* grandparent = parent->_parent;
				if (parent == grandparent->_left)
				{
					Node* uncle = grandparent->_right;
					//如果uncle存在且为红,则将parent和uncle变黑,grandparent变红
					if (uncle && uncle->_col == RED)
					{
						parent->_col=uncle->_col = BLACK;
						grandparent->_col = RED;
					}
					//uncle不存在或者为黑
					else
					{
						//将grandparent右旋,grandparent和cur变为红,parent变为黑
						if (cur == parent->_left)
						{
							RotateR(grandparent);
							cur->_col=grandparent->_col = RED;
							parent->_col = BLACK;
						}
						//将parent左旋,grandparent右旋,将cur变为黑,parent和grandparent变为红
						else
						{
							RotateL(parent);
							RotateR(grandparent);
							parent->_col = grandparent->_col = RED;
							cur->_col = BLACK;
						}
						break;
					}
				}
				else
				{
					Node* uncle = grandparent->_left;
					//如果uncle存在且为红,则将parent和uncle变黑,grandparent变红
					if (uncle && uncle->_col == RED)
					{
						parent->_col = uncle->_col = BLACK;
						grandparent->_col = RED;
					}
					//uncle不存在或者为黑
					else
					{
						//将grandparent左旋,grandparent和cur变为红,parent变为黑
						if (cur == parent->_right)
						{
							RotateL(grandparent);
							cur->_col = grandparent->_col = RED;
							parent->_col = BLACK;
						}
						//将parent右旋,grandparent左旋,将cur变为黑,parent和grandparent变为红
						else
						{
							RotateR(parent);
							RotateL(grandparent);
							parent->_col = grandparent->_col = RED;
							cur->_col = BLACK;
						}
						break;
					}
				}
			}
			//把根节点变为黑
			_root->_col = BLACK;
			return make_pair(iterator(ret), true);
	    }
		bool _IsRBTree(Node* root,int count,int blacknum)
		{
			if (root == nullptr)
			{
				if (count != blacknum)
				{
					return false;
				}
				return true;
			}
			if (root->_col == BLACK)
				count++;

			return _IsRBTree(root->_left, count, blacknum) &&
				_IsRBTree(root->_right, count, blacknum);
		}
		bool IsRBTree()
		{
			if (_root->_col == RED)
			{
				return false;
			}
			int blacknum = 0;
			Node* cur = _root;
			while (cur)
			{
				if (cur->_col == BLACK)
					blacknum++;
				cur = cur->_left;
			}
			return _IsRBTree(_root, 0, blacknum);
		}
		void _InOrder(Node* root)
		{
			KeyOfT okt;
			if (root == nullptr)
			{
				return;
			}
			_InOrder(root->_left);
			cout << kof(root->_data) << " ";
			_InOrder(root->_right);
		}
		void InOrder()
		{
			_InOrder(_root);
			cout << endl;
		}
	private:

		//左单旋
		void RotateL(Node* parent)
		{
			Node* subR = parent->_right;
			Node* subRL = subR->_left;
			Node* grandparent = parent->_parent;
			parent->_right = subRL;
			if (subRL)
			{
				subRL->_parent = parent;
			}
			subR->_left = parent;
			parent->_parent = subR;
			if (parent == _root)
			{
				_root = subR;
			}
			else
			{
				if (grandparent->_left == parent)
					grandparent->_left = subR;
				else
					grandparent->_right = subR;
			}
			subR->_parent = grandparent;
		}
		//右单旋
		void RotateR(Node* parent)
		{
			Node* subL = parent->_left;
			Node* subLR = subL->_right;
			Node* grandparent = parent->_parent;
			parent->_left = subLR;
			if (subLR)
			{
				subLR->_parent = parent;
			}
			subL->_right = parent;
			parent->_parent = subL;
			if (parent == _root)
			{
				_root = subL;
			}
			else
			{
				if (grandparent->_left == parent)
					grandparent->_left = subL;
				else
					grandparent->_right = subL;
			}
			subL->_parent = grandparent;
		}
		//左右双旋
		void RotateLR(Node* parent)
		{
			Node* subL = parent->_left;
			Node* subLR = subL->_right;
			RotateL(subL);
			RotateR(parent);
		}
		//右左双旋
		void RotateRL(Node* parent)
		{
			Node* subR = parent->_right;
			Node* subRL = parent->_left;
			RotateR(subR);
			RotateL(parent);
		}
		Node* _root;
	};
}

  • 22
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
抱歉,我是一名语言模型AI,无法为您提供演示实时代码功能。但是,我可以向您解释红黑树的基本原理和操作。红黑树是一种自平衡二叉搜索树,它的每个节点都有一个颜色属性,红色或黑色,具有以下特性: 1. 根节点为黑色。 2. 所有叶子节点(NIL节点)为黑色。 3. 如果一个节点为红色,则它的两个子节点必须都为黑色。 4. 从任意一个节点到其每个叶子节点的所有路径都包含相同数量的黑色节点。 红黑树的基本操作包括插入、删除和查找。插入和删除操作会破坏红黑树的平衡性,需要通过旋转和重新着色来修复平衡。查找操作与二叉搜索树相同,具有O(log n)的时间复杂度。 以下是红黑树的插入操作的伪代码: 1. 新节点插入到红黑树中,颜色为红色。 2. 如果新节点的父节点为黑色,则不需要做任何操作,树仍然平衡。 3. 如果新节点的父节点为红色,需要进行以下操作: (1) 如果新节点的叔节点(父节点的兄弟节点)为红色,则将父节点和叔节点涂黑,祖父节点涂红,然后将当前节点指向祖父节点,重复步骤2。 (2) 如果新节点的叔节点为黑色,并且新节点是父节点的右子节点(父节点为祖父节点的左子节点),则将父节点左旋转,将当前节点指向父节点,重复步骤4。 (3) 如果新节点的叔节点为黑色,并且新节点是父节点的左子节点(父节点为祖父节点的右子节点),则将父节点右旋转,将当前节点指向父节点,重复步骤4。 4. 将父节点涂黑,祖父节点涂红,然后进行以下操作: (1) 如果当前节点是父节点的左子节点,将祖父节点右旋转。 (2) 如果当前节点是父节点的右子节点,将祖父节点左旋转。 以上是红黑树的基本操作,希望能够帮助您理解红黑树的原理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我要满血复活

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值