模拟实现红黑树超详解(C++)

在这里插入图片描述

😇 😇大家好,我是bug!今天我们就要讲讲红黑树的性质以及模拟实现了
(代码可能会有一点问题,请各位老铁指正 😘 😘 )

一、红黑树

✏️ ✏️ 红黑树(Red Black Tree): 是一种自平衡二叉查找树。红黑树是一种特化的AVL树(平衡二叉树),都是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能。

🌻 🌻 那红黑树是怎么去实现它的平衡的呢?

根据如下的五点规则:
🌱 (1)根结点为黑色结点。
🌱 (2)结点颜色只有红色和黑色。
🌱 (3)叶子结点都是黑色的。(这里的叶子结点指的是NIL)
🌱 (4)没有连续的红色结点。
🌱 (5)任意根到叶子路径上的黑色结点个数一致。

(1)、(2)两点应该不用解释了吧,嘿嘿 😜 😜 。 我们从第三点开始。

在这里插入图片描述

✒️ ✒️ 第三点:
这里的叶子结点和我们之前学习的叶子结点概念不同,如图:
我们之前学习的叶子结点指的是两个孩子结点都是空结点(NIL)如A和C。这里的叶子指的是(NIL)空结点。

✒️ ✒️ 第四点和第五点:
红黑树的平衡控制主要的是通过这两条规则决定的。红黑树的平衡要求是最长路径的结点个数不能够超过最短路径的结点个数的两倍。

🌻 🌻 小伙伴们可以想象出平衡是怎么实现的吗?(通过后两条规则)

通过这两点我们可以知道,最短路径上的结点一定全是黑结点。然而红色结点不能够连续,那么最长路径上的结点一定是红色结点和黑色结点交替排列,而且最后一个结点一定是红色的(这里我们计算不纳入叶子结点进行计算),同时根结点一定是黑色的。所以最长路径一定是最短路径的两倍。 🔍 🔍

🌻 🌻 小伙伴们是不是有所疑惑,相比于AVL树,红黑树的平衡要求并没有那么严格,那么红黑树和AVL树的区别究竟在哪?红黑树提出的意义又在哪里呢?(AVL树:任意结点的左右子树的高度差不能超过1 )

和AVL树一样,红黑树的增删查改的时间复杂度都是O(logN)。我们以红黑树的最坏情况进行计算:(即计算最长路径)当我们查找时,其时间复杂度为O(2logN),但是我们仔细想想,其实两倍没啥区别。以十亿个数据为例:其实也就是2^30,取对数后也就大概30次的样子,对于计算机的效率而言,30次和60次就没有什么区别。 🔍 🔍

但是相比于AVL树严格的规则,红黑树的优势就体现出来了。红黑树旋转调整的次数不会超过AVL树,旋转付出的代价在效率上会有所体现。随着我们插入数据的增多,AVL树旋转的次数增长一定会超过红黑树。所以综合之下,大多数地方采用的都是红黑树(包括我们后面封装的map和set,它们的底层也是红黑树)。 🔍 🔍

☀️ ☀️ 关于路径:如上图,其中的路径不是两条,而是四条路径。因为路径指的是从根到任意叶子(NIL)。


在这里插入图片描述

对于红黑树而言,它的插入和删除是极为复杂的,下面我们就要一一进行介绍。 🌹 🌹


二、红黑树的插入

🍁 🍁 红黑树的插入有四种情况,下面我们会以最简单的例子进行分析:


🌻 🌻 红黑树的结点插入,我们创建结点时默认采用红色,为什么不采用黑色呢?
(小伙伴们可以先思考一下,我们后面在讲,嘿嘿。)


🌳 🌳 1、插入红色结点,且父亲结点是黑色。

不需要处理,不会影响路径上黑色结点个数。

🌳 🌳 2、插入红色结点,父亲结点红色。

因为父亲结点是红色,所以祖父结点一定是黑色,那我们就要根据叔叔结点进行判断,所以分如下情况:

🍄 (1)叔叔结点存在且为红色

如下图,我们在p结点的下方(左右都一样)插入一个红色结点。在这里插入图片描述
这时候就违反了我们的规则四,所以我们进行修正,如下图:
在这里插入图片描述

📣 📣 将p结点变成黑色,但是这样我们左侧路径就会多出一个黑色结点,所以我们要把右侧的u结点也变黑。

如果你觉得这样就没问题了,那就是大错特错了。

当g是根结点的时候,g现在是黑色,那么就不用修改。
当g不是根节点的时候,那图中的树一定是某个结点的子树,这时候我们把p和u都变黑后,这五条路径比其他路径的黑色结点多1,所以我们把g结点变红来保持黑色结点的个数不变。
🔍 🔍

但是还有一个问题,我们不知道g结点的父亲结点是黑色还是红色,所以我们要进行向上调整,如果g的父亲是黑色,那就不用修改,如果是红色,那就要进行操作,一直向上调整。

🍄 (2)叔叔结点存在且为黑色

在这里插入图片描述

📣 📣 这里我们采用右单旋加变色,以g作为旋转点进行右单旋,把p变成黑色,把g变成红色。

在这里插入图片描述

看到这里的时候是不是感觉有点不对劲,在上图中左侧和右侧的黑色结点的个数不一致。
其实这里的完整图片并没有画全,最左侧的结点其实并不是新增结点,如下图:

在这里插入图片描述
当我们完成了叔叔结点为红色的跟新后,就会出现当前这种情况:
在这里插入图片描述
旋转变色调整之后,如图:
在这里插入图片描述

🍄 (3)叔叔结点不存在。

1、“直线形状”

在这里插入图片描述

📣 📣 这里我们采用右单旋加变色,以g为旋转点,进行右单旋,同时把p变成黑色,g变成红色。

2、“折线形状”*

在这里插入图片描述

📣 📣 我们采用左右双旋加变色,先以p为旋转点进行左单旋,再以g为旋转点进行右单旋,把p变黑,g变红。

ok,红黑树的插入就分如上几种情况。

现在我们来讲讲为什么红黑树结点的默认颜色设置为红色,因为假设我们插入的结点是黑色结点,那么我们一定会违反规则五(黑色结点的个数一致),如果我们插入的结点是红色结点,那么我们可能会违反规则四(没有连续的红色结点)。

那我们到底是选择违反规则四还是规则五呢?
看哪个代价小,选择默认为红色结点可能没有影响,或者影响包含该红色结点的路径。但是如果我们选择黑色,那么就会影响所有的路径,代价太大,所以我们选择默认红色。


在这里插入图片描述

哈哈,如果大家觉得还好的话,那我们就继续下面红黑树的删除操作了。(嘿嘿,删除操作比插入更加复杂的)


三、红黑树的删除

红黑树的删除方法其实本质算得上是穷举法,就是把所有可能的情况都考虑包含进去,好了废话不多说,开始正题。
(摔,画完了才发现u标错了,懒得改了)
还是进行分类讨论:

🌲 1、删除的结点没有孩子结点

🌴 🌴 (1)删除的结点是红色结点

📣 📣 直接删除就可以,不会违反规则。

在这里插入图片描述

🌴 🌴 (2)删除的结点是黑色结点

如果删除的结点是黑色结点,这就比较麻烦了,因为不论怎么操作黑色结点的数量都减少了,这时候我们就要进行进一步划分了:

🍎 1、u为黑色结点

🍋 🍋 注意❗️ ❗️

这里的uR和uL不能为黑色结点,因为一旦是黑色结点就会打破规则五。所以下面针对红色结点和空结点进行分析:

🍔 🍔一、如果uR存在且为红色结点(p颜色无要求):
在这里插入图片描述

📣 📣 以p为旋转点进行左单旋,交换p和u颜色,uR变黑。(保证黑色结点的个数不发生变化)

在这里插入图片描述
🍔 🍔二、如果uL结点存在且为红色结点(p颜色无要求):
在这里插入图片描述

📣 📣 先以u作为旋转点进行右单旋,同时把uL结点变黑。

在这里插入图片描述

📣 📣 然后再以p作为旋转点进行左单旋,交换p和uL的颜色。

在这里插入图片描述

🍔 🍔三、如果uR和uL结点都不存在:
这里我们就要考虑p结点的颜色了。
🍓 (1)p为黑色时
在这里插入图片描述
这种情况最为复杂,因为删除黑色结点一定会违反规则五(黑色节点的个数保持一致)。

📣 📣 我们的操作是删除结点后,将u结点变红,先保持当前左右结点的个数相同,然后开始向上调整。

在这种情形下又有如下三种情况:
🍑 🍑 情况一:向上调整碰上红色结点
在这里插入图片描述

📣 📣 删除结点后,把u变红,暂时保持平衡。

在这里插入图片描述

📣 📣 再把碰上的红色结点变黑,同时把p的兄弟结点变红。(这时候黑色结点的个数就恢复了,停止调整)

在这里插入图片描述
🍑 🍑 情况二:向上调整碰到黑色结点,而且p结点的兄弟结点也是黑色。

在这里插入图片描述

📣 📣 删除结点后,把u结点变成红色,继续向上调整,直到调整到根结点或者红色结点。(也就是第一种情况)

在这里插入图片描述

🍑 🍑 情况三:向上调整碰到黑色结点,而且兄弟结点为红色结点。
在这里插入图片描述

📣 📣 删除结点后,把u变红,向上调整。

在这里插入图片描述

📣 📣 碰到p的红色兄弟结点s,我们就以g为旋转点,进行左旋的操作,再把sL结点变红,s结点变黑。(停止调整,这时候黑色结点的个数恢复了)

在这里插入图片描述

🍓 (2)p为红色时
在这里插入图片描述

📣 📣 直接删除结点,再把u结点变红,把p结点变黑。(黑色结点的个数没有改变)

🍎 2、u为红色结点

那么uR和uL一定都存在且为黑色结点。
在这里插入图片描述

📣 📣 以p为旋转点进行左单旋,将p变红,u变黑。

在这里插入图片描述

🌲 2、删除的结点有一个孩子结点

如果删除的结点为红色结点,不可能的。因为红色结点它的孩子结点一定是黑色结点,但是如果只有一个黑色结点的话那么就会违反规则五,所以删除的结点一定为黑色结点,那么孩子结点一定不能影响黑色结点的个数,所以孩子结点一定为红色结点。那么针对这种情况:

📣 📣 我们只需要把黑色结点删除,同时把孩子结点变黑,顶替上去即可。(这里p结点的颜色无影响)

在这里插入图片描述

🌲 3、删除的结点有两个孩子结点

📣 📣 如果删除结点有两个孩子结点,那么我们采用替换法进行删除。即可以用左子树的最右结点或者右子树的最左结点来替代删除结点,删除替代结点的同时把替代结点的数据交给之前的结点。删除替代结点又会回到我们的第一种(没有孩子结点)或者第二种情况(有一个孩子结点)。


(删除结点这块参考了不少的资料,上面的分析可能还有一些不足)
在这里插入图片描述


四、红黑树的迭代器

✏️ ✏️ 和list的迭代器类似,都是对结点进行封装。
“*”和“->”的重载比较简单,但是对自增自减的重载就有点麻烦了。如下图(这里以前置自增为例):

🍉 🍉 (1)_pnode的右子树不为空
在这里插入图片描述
红黑树中重载自增,就是按照数据增大顺序。如果_pnode的右子树不为空,那我们直接去找右子树的最左结点,也就是右子树中序遍历的第一个结点。

🍉 🍉 (2)_pnode的右子树为空
在这里插入图片描述
因为右子树为空,那么就要向上去找与_pnode指向相邻的数据,如果_pnode是父亲的右孩子,那么就要继续向上找,直到_pnode是父亲的左孩子,这个时候自增结果就是父亲。(即图中的根结点)
这里我们迭代器的begin里面是最左结点,end里面是nullptr。
当我们的_pnode指向的数据最大时,继续自增的结果就是与end相等,这是就会结束。

反向迭代器:可以理解为迭代器适配器,里面封装了正向迭代器,同时反向迭代器的rbegin里面是最右结点,rend里面是nullptr。
当我们完成了自减的重载,我们就可以实现反向迭代器了。


🍋 🍋 注意❗️ ❗️

有的地方的红黑树的实现借用了一个头结点,那么迭代器end里面就是头结点的指针。(如下图)

在这里插入图片描述
头结点的父亲指向的是根结点,同时根结点的父亲指向的是头结点,头结点的左孩子指向的是最左结点,头结点的右孩子指向的是最右结点。这种方式有助于迭代器遍历找到头尾。(小伙伴们感兴趣也可以去尝试一下)
在这里插入图片描述


五、红黑树的模拟实现

🍒 🍒 模拟实现红黑树的代码⬇️ ⬇️ :

#include<iostream>
#include<assert.h>

using std::cin;
using std::cout;
using std::endl;
using std::make_pair;
using std::pair;

enum Colour { RED, BLACK, };

namespace lz
{
	template<class K,class V>
	struct RBTreeNode
	{
		typedef RBTreeNode<K, V>* pNode;
		typedef RBTreeNode<K, V> Node;

		//三叉链
		pNode _left;
		pNode _right;
		pNode _parent;

		//颜色,红黑树不需要平衡因子
		Colour _col;
		pair<K, V> _kv;

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

	template<class K, class V, class Ref, class Ptr>
	struct Iterator
	{
		typedef RBTreeNode<K, V>* pNode;
		typedef RBTreeNode<K, V> Node;
		typedef Iterator<K, V, Ref, Ptr> Self;
		typedef Ref Reference;
		typedef const Ref const_Reference;
		typedef Ptr Pointer;
		typedef const Ptr const_Pointer;

	public:
		Iterator(pNode pnode = nullptr)
			:_pnode(pnode)
		{}

		pNode _pnode;

		Reference operator*() { return _pnode->_kv; }
		const_Reference operator*()const { return _pnode->_data; }
		Pointer operator->() { return &(operator*()); }
		const_Pointer operator->()const { return &(operator*()); }
		bool operator!=(const Self& s)const { return s._pnode != _pnode; }
		bool operator==(const Self& s)const { return s._pnode == _pnode; }

		void increasement()
		{
			//如果右子树存在,那么我们去访问右子树的最左结点
			//也就是中序的第一个结点。
			if (_pnode->_right)
			{
				pNode left = _pnode->_right;
				while (left->_left)
				{
					left = left->_left;
				}

				_pnode = left;
			}
			else //cur的右子树为NIL,上溯查找
			{
				//如果父亲为空,则_pnode为根结点父亲不为空,
				//那么就向上去找不是父亲右孩子的结点,它的父亲就是我们要访问的结点
				pNode cur = _pnode;
				pNode parent = cur->_parent;
				while (parent && cur == parent->_right)
				{
					cur = parent;
					parent = parent->_parent;
				}

				_pnode = parent;
			}
		}

		void decreasement()
		{
			if (_pnode->_left)
			{
				//左子树不为空,去找左子树的最右结点
				pNode right = _pnode->_left;
				while (right->_right)
				{
					right = right->_right;
				}

				_pnode = right;
			}
			else//cur的左子树不存在,上溯查找父亲
			{
				//如果去找不是父亲左孩子的结点,它的父亲就是我们要访问的结点
				pNode cur = _pnode;
				pNode parent = cur->_parent;
				while (parent && cur == parent->_left)
				{
					cur = parent;
					parent = parent->_parent;
				}

				_pnode = parent;
			}
		}

		Self& operator++() { increasement(); return *this; }
		Self& operator--() { decreasement(); return *this; }
		Self operator++(int)
		{
			pNode tmp = _pnode; increasement(); return tmp;
		}
		Self operator--(int)
		{
			pNode tmp = _pnode; decreasement(); return tmp;
		}

	};

	//反向迭代器(迭代器适配器:里面封装了正向迭代器)
	template<class Iterator>
	struct reverse_iterator
	{
		typedef typename Iterator::Reference Reference;
		typedef typename Iterator::const_Reference const_Reference;
		typedef typename Iterator::Pointer Pointer;
		typedef typename Iterator::const_Pointer const_Pointer;
		typedef reverse_iterator<Iterator> Self;

		reverse_iterator(Iterator it)
			:_it(it)
		{}

		Reference operator*() { return *_it; }
		const_Reference operator*()const { return *_it; }
		Pointer operator->() { return *operator* (); }
		const_Pointer operator->()const { return &operator* (); }

		Self& operator++() { --_it; return *this; }
		Self operator++(int) { Iterator tmp = _it--; return tmp; }
		Self& operator--() { ++_it; return *this; }
		Self operator--(int) { Iterator tmp = _it++; return tmp; }
		bool operator!=(const Self& s)const { return _it != s._it; }
		bool operator==(const Self& s)const { return _it == s._it; }

		Iterator _it;
	};

	template<class K, class V>
	struct RBTree
	{
		typedef RBTree<K, V> Self;
		typedef RBTreeNode<K, V>* pNode;
		typedef RBTreeNode<K, V> Node;
		typedef Iterator<K, V, pair<K, V>&, pair<K, V>*> tree_iterator;
		typedef 
			Iterator<K, V, const pair<K, V>&, const pair<K, V>*> tree_const_iterator;
		typedef reverse_iterator<tree_iterator> tree_reverse_iterator;
		typedef reverse_iterator<tree_const_iterator> tree_reverse_const_iterator;

	private:
		pNode _root;

	public:
		RBTree()
			:_root(nullptr)
		{}

		//正向迭代器
		tree_iterator begin()
		{
			pNode cur = _root;
			while (cur->_left)
				cur = cur->_left;
			return tree_iterator(cur);
		}
		tree_iterator end() { return tree_iterator(nullptr); }

		tree_const_iterator cbegin()const
		{
			pNode cur = _root;
			while (cur->_left)
				cur = cur->_left;
			return tree_const_iterator(cur);
		}
		tree_const_iterator cend()const { return tree_const_iterator(nullptr); }

		//反向迭代器
		tree_reverse_iterator rend() 
		{
			return tree_reverse_iterator(tree_iterator(nullptr));
		}
		tree_reverse_iterator rbegin() 
		{
			pNode cur = _root;
			while (cur->_right)
				cur = cur->_right;
			return tree_reverse_iterator(tree_iterator(cur));
		}

		tree_reverse_const_iterator rcend()const 
		{
			return tree_reverse_const_iterator(tree_const_iterator(nullptr));
		}
		tree_reverse_const_iterator rcbegin()const
		{
			pNode cur = _root;
			while (cur->_right)
				cur = cur->_right;
			return tree_reverse_const_iterator(tree_const_iterator(cur));
		}

		//内部拷贝
		void _CopyTree(const pNode& root)
		{
			if (root == nullptr)
				return;

			insert(root->_data);

			_CopyTree(root->_left);
			_CopyTree(root->_right);
		}

		//拷贝构造函数
		RBTree(const Self& t)
		{
			_root = nullptr;
			_CopyTree(t._root);
		}

		void clear(pNode& root)
		{
			if (root == nullptr)
				return;

			clear(root->_left);
			clear(root->_right);
			delete root;
		}

		~RBTree()
		{
			clear(_root);
		}

		//对=进行重载
		Self& operator=(const Self& t)
		{
			Self tmp(t);
			std::swap(tmp._root, _root);
			return *this;
		}

		//查找
		tree_iterator find(const K& key)const
		{
			if (_root == nullptr)
				return tree_iterator(nullptr);

			pNode cur = _root;
			while (cur)
			{
				if (cur->_kv.first > key)
					cur = cur->_left;
				else if (cur->_kv.first < key)
					cur = cur->_right;
				else
					return tree_iterator(cur);
			}

			return tree_iterator(nullptr);
		}

		//插入数据
		pair<tree_iterator, bool> insert(const pair<K, V>& kv)
		{
			//如果根节点为空
			if (_root == nullptr)
			{
				_root = new Node(kv, BLACK);
				return make_pair(tree_iterator(_root), true);
			}

			//如果根节点不为空,去找插入位置
			pNode cur = _root;
			pNode parent = _root;
			while (cur)
			{
				//如果cur中的key大于kv中的key,去左边找
				if (cur->_kv.first > kv.first)
				{
					parent = cur;
					cur = cur->_left;
				}
				//如果cur中的key小于kv中的key,去右边找
				else if (cur->_kv.first < kv.first)
				{
					parent = cur;
					cur = cur->_right;
				}
				else//找到了和插入数据的key相同的数据,插入失败
					//同时返回原有数据的的指针
				{
					return make_pair(tree_iterator(cur), false);
				}
			}

			pNode newNode = new Node(kv);
			cur = newNode;
			//找到了插入的位置,判断位置是在parent左边还是右边
			if (parent->_kv.first > kv.first)
			{
				newNode->_parent = parent;
				parent->_left = newNode;
			}
			else if (parent->_kv.first < kv.first)
			{
				newNode->_parent = parent;
				parent->_right = newNode;
			}

			//插入完成
			//开始进行平衡操作(变色+旋转)

			//如果parent存在:《1》parent为BLACK,不操作
			//《2》parent为RED,如果uncle为RED,直接把uncle和parent变红
			//如果uncle为BLACK或者不存在,进行旋转和变色
			while (parent && parent->_col == RED)
			{
				pNode grandFather = parent->_parent;

				//注意!!这里grandFather一定存在,因为parent为红色结点,如果
				//grandFather不存在,parent就是根节点,违反了规则。

				//如果parent是grandFather的左孩子
				if (grandFather->_left == parent)
				{
					//如果uncle不为空而且为红色,uncle和parent直接变黑
					pNode uncle = grandFather->_right;
					if (uncle && uncle->_col == RED)
					{
						parent->_col = BLACK;
						uncle->_col = BLACK;
						grandFather->_col = RED;

						cur = grandFather;
						parent = grandFather->_parent;
					}
					//如果uncle为空或者uncle不为空且为而且为黑色
					else
					{
						//如果cur是parent的左孩子,进行右单旋+变色
						//如果这里grandFather是根节点,
						//则parent最后要变成黑色,最后调整
						if (parent->_left == cur)
						{
							RotateR(parent->_parent);
							parent->_col = BLACK;
							grandFather->_col = RED;
							break;
						}
						//如果cur是parent的右孩子,进行左右双旋+变色
						//如果这里grandFather是根节点,
						//则cur最后要变成黑色,最后调整
						else if (parent->_right == cur)
						{
							RotateL(parent);
							RotateR(grandFather);
							cur->_col = BLACK;
							grandFather->_col = RED;
							break;
						}
					}
				}
				//如果parent是grandFather的右孩子,和上面情况类似
				else if (grandFather->_right == parent)
				{
					pNode uncle = grandFather->_left;
					//如果uncle存在,而且为红色
					if (uncle && uncle->_col == RED)
					{
						parent->_col = BLACK;
						uncle->_col = BLACK;
						grandFather->_col = RED;
						//继续往上处理
						cur = grandFather;
						parent = grandFather->_parent;
					}
					//uncle不存在,或者存在为黑色
					else
					{
						//如果cur是parent的右孩子
						if (parent->_right == cur)
						{
							RotateL(parent->_parent);
							parent->_col = BLACK;
							grandFather->_col = RED;
							break;
						}
						//cur是parent的左孩子
						else if (parent->_left == cur)
						{
							RotateR(parent);
							RotateL(grandFather);
							cur->_col = BLACK;
							grandFather->_col = RED;
							break;
						}
					}
				}
			}

			_root->_col = BLACK;
			return make_pair(tree_iterator(newNode), true);
		}

		//右单旋
		void RotateR(pNode parent)
		{
			pNode grandFather = parent->_parent;
			pNode subL = parent->_left;
			pNode subLR = subL->_right;

			if (subLR)
				subLR->_parent = parent;

			subL->_right = parent;
			subL->_parent = grandFather;
			parent->_parent = subL;
			parent->_left = subLR;

			//如果parent是根节点
			if (parent == _root)
				_root = subL;
			else//如果parent不是根节点	
			{
				//如果parent是grandFather左孩子
				if (grandFather->_left == parent)
					grandFather->_left = subL;
				else if (grandFather->_right == parent)
					grandFather->_right = subL;
			}
		}

		//左单旋
		void RotateL(pNode parent)
		{
			pNode grandFather = parent->_parent;
			pNode subR = parent->_right;
			pNode subRL = subR->_left;

			if (subRL)
				subRL->_parent = parent;

			subR->_left = parent;
			subR->_parent = grandFather;
			parent->_parent = subR;
			parent->_right = subRL;

			if (parent == _root)
				_root = subR;
			else
			{
				if (grandFather->_left == parent)
					grandFather->_left = subR;
				else if (grandFather->_right == parent)
					grandFather->_right = subR;
			}
		}

		//进行删除结点
		void deleteNode(pNode node)
		{
			pNode replace = nullptr;
			pNode parent = nullptr;
			// 存在两个孩子结点
			if (node->_left != nullptr && node->_right != nullptr)
			{
				pNode left = node->_right;
				while (left && left->_left)
				{
					left = left->_left;
				}
				node->_kv = left->_kv;//覆盖值
				deleteNode(left);//递归删除,只可能递归一次
				return;
			}
			else
			{
				//有一个孩子结点或者没有孩子结点
				// 判断删除的结点是否是根结点
				if (node->_parent == nullptr)
				{
					this->_root =
						(node->_left != nullptr ? node->_left : node->_right);
					replace = this->_root;
					if (this->_root != nullptr)
						this->_root->_parent = nullptr;
				}
				else
				{
					// 不是根结点	
					pNode child =
						(node->_left != nullptr ? node->_left : node->_right);
					if (node->_parent->_left == node)
						node->_parent->_left = child;
					else
						node->_parent->_right = child;

					if (child != nullptr)
						child->_parent = node->_parent;
					replace = child;
					parent = node->_parent;
				}
			}
			//红色结点直接删除,不用处理
			if (node->_col == BLACK)
				_deleteFixUp(replace, parent);
		}

		//修复颜色
		void _deleteFixUp(pNode replace, pNode parent)
		{
			pNode brother = nullptr;
			//parent不是空结点,代替结点是黑色结点时
			while ((replace == nullptr || replace->_col == BLACK)
				&& replace != this->_root)
			{
				if (parent->_left == replace)
				{
					brother = parent->_right;
					// 兄弟结点是红色结点,兄弟结点变黑,父亲结点变红
					//parent左旋,replace的兄弟变成了黑色
					if (brother->_col == RED)
					{
						brother->_col = BLACK;
						parent->_col = RED;
						RotateL(parent);
						brother = parent->_right;
					}
					// 经过上面,不管进没进if,兄弟都成了黑色
					// 兄弟结点是黑色结点,兄弟的两个孩子结点也是黑色
					if ((brother->_left == nullptr
						|| brother->_left->_col == BLACK)
						&& (brother->_right == nullptr
							|| brother->_right->_col == BLACK))
					{
						// 如果parent此时为红,把兄弟结点和父亲结点交换颜色
						if (parent->_col == RED)
						{
							parent->_col = BLACK;
							brother->_col = RED;
							break;
						}
						else
						{
							//parent为黑,先把兄弟结点变红保持子树平衡,
							//然后向上调整
							brother->_col = RED;
							replace = parent;
							parent = replace->_parent;
						}
					}
					else
					{
						//兄弟结点是黑色结点,左孩子存在且为红色结点
						if (brother->_left != nullptr && brother->_left->_col == RED)
						{
							brother->_left->_col = parent->_col;
							parent->_col = BLACK;
							RotateR(brother);
							RotateL(parent);
						}
						//兄弟结点是黑色结点,右孩子存在且为红色结点
						else if (brother->_right != nullptr
							&& brother->_right->_col == RED)
						{
							brother->_col = parent->_col;
							parent->_col = BLACK;
							brother->_right->_col = BLACK;
							RotateL(parent);
						}
						break;
					}
				}
				else
				{
					//对称情况
					brother = parent->_left;
					//兄弟结点是红色结点,兄弟结点变黑,父亲结点变红
					//parent右旋,replace的兄弟结点变成了黑色
					if (brother->_col == RED)
					{
						brother->_col = BLACK;
						parent->_col = RED;
						RotateR(parent);
						brother = parent->_left;
					}
					// 经过上面,不管进没进if,兄弟结点都成了黑色
					// 兄弟结点是黑色结点,兄弟的两个孩子结点也是黑色
					if ((brother->_left == nullptr
						|| brother->_left->_col == BLACK)
						&& (brother->_right == nullptr
							|| brother->_right->_col == BLACK))
					{
						// 如果parent此时为红,把兄弟结点和父亲结点交换颜色
						if (parent->_col == RED)
						{
							parent->_col = BLACK;
							brother->_col = RED;
							break;
						}
						else
						{
							//parent为黑,先把兄弟结点变红保持子树平衡,
							//然后向上调整
							brother->_col = RED;
							replace = parent;
							parent = replace->_parent;
						}
					}
					else
					{
						//兄弟结点是黑色结点,左孩子存在且为红色结点
						if (brother->_right != nullptr
							&& brother->_right->_col == RED)
						{
							brother->_right->_col = parent->_col;
							parent->_col = BLACK;
							RotateL(brother);
							RotateR(parent);
						}
						//兄弟结点是黑色结点,右孩子存在且为红色结点
						else if (brother->_left != nullptr
							&& brother->_left->_col == RED)
						{
							brother->_col = parent->_col;
							parent->_col = BLACK;
							brother->_left->_col = BLACK;
							RotateR(parent);
						}
						break;
					}
				}
			}
			//删除结点只有一个孩子结点,如果是根,将其涂黑。
			if (replace != nullptr)
				replace->_col = BLACK;
		}

		//中序遍历
		void _InOder(const pNode& root)
		{
			if (root == nullptr)
			{
				return;
			}

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

		void InOder()
		{
			if (_root == nullptr)
				return;

			_InOder(_root);
		}

		//测试RBTee是否错误
		bool _IsRBTree(const Node* root, int blackCount, int count)
		{
			if (root == nullptr)
			{
				if (count != blackCount)
				{
					cout << "黑色节点的个数不一致" << endl;
					return false;
				}
				return true;
			}

			//判断红色节点的parent是否是红色节点
			if (root->_col == RED && root->_parent->_col == RED)
			{
				cout << "有连续的红色结点" << endl;
				return false;
			}

			//黑色节点时,++
			if (root->_col == BLACK)
			{
				count++;
			}

			return _IsRBTree(root->_left, blackCount, count)
				&& _IsRBTree(root->_right, blackCount, count);
		}

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

			pNode cur = _root;
			//参考值
			int blackCount = 0;
			while (cur)
			{
				//统计黑色结点个数作为参考
				if (cur->_col == BLACK)
					blackCount++;
				cur = cur->_left;
			}

			return _IsRBTree(_root, blackCount, 0);
		}


	};
}

void Test1()
{
	lz::RBTree<int, int> t1;
	int i = 1000;

	while (i)
	{
		t1.insert(make_pair<int, int>(0 + i, 1));
		i--;
	}

	while (i != 500)
	{
		i++;
		t1.deleteNode(t1.find(i)._pnode);

	}
	t1.InOder();
	cout << t1.IsRBTree() << endl;

}

void Test2()
{
	lz::RBTree<int, int> t1;
	t1.insert(make_pair<int, int>(1, 2));
	t1.insert(make_pair<int, int>(2, 2));
	t1.insert(make_pair<int, int>(3, 2));
	t1.insert(make_pair<int, int>(4, 2));
	lz::RBTree<int, int>::tree_iterator it = t1.begin();
	while (it != t1.end())
	{	
		cout << (*it).first << " : " << (*it).second << endl;
		it++;
	}
	lz::RBTree<int, int>::tree_iterator it1 = t1.begin();
	it1++;
	it1++;
	cout << (*it1).first << " : " << (*it1).second << endl;

	--it1;
	cout << (*it1).first << " : " << (*it1).second << endl;
	cout << endl;
}

void Test3()
{
	lz::RBTree<int, int> t1;
	t1.insert(make_pair<int, int>(1, 2));
	t1.insert(make_pair<int, int>(2, 2));
	t1.insert(make_pair<int, int>(3, 2));
	t1.insert(make_pair<int, int>(4, 2));
	lz::RBTree<int, int>::tree_const_iterator it1 = t1.cbegin();
	while (it1 != t1.cend())
	{
		/*(*it1).first = 20;
		(*it1).second = 20;*/
		cout << (*it1).first << " : " << (*it1).second << endl;
		++it1;
	}
	cout << endl;

	t1.InOder();
	cout << endl;

	lz::RBTree<int, int>::tree_iterator it2 = t1.begin();
	while (it2 != t1.end())
	{
		(*it2).first = 20;
		(*it2).second = 10;
		cout << (*it2).first << " : " << (*it2).second << endl;
		++it2;
	}
}

void Test4()
{
	lz::RBTree<int, int> t1;
	t1.insert(make_pair<int, int>(1, 2));
	t1.insert(make_pair<int, int>(2, 2));
	t1.insert(make_pair<int, int>(3, 2));
	t1.insert(make_pair<int, int>(4, 2));
	lz::RBTree<int, int>::tree_iterator it = t1.find(1);
	cout << (*it).first << " : " << (*it).second << endl;

	it->first = 3;
	cout << it->first << " : " << it->second << endl;

	lz::RBTree<int, int>::tree_const_iterator it1 = t1.cbegin();
	cout << it1->first << " : " << it1->second << endl;

}

void Test5()
{
	lz::RBTree<int, int> t1;
	t1.insert(make_pair<int, int>(1, 2));
	t1.insert(make_pair<int, int>(2, 2));
	t1.insert(make_pair<int, int>(3, 2));
	t1.insert(make_pair<int, int>(4, 2));
	//无const修饰
	lz::RBTree<int, int>::tree_reverse_iterator it = t1.rbegin();
	while (it != t1.rend())
	{
		//(*it).second = 10;
		cout << (*it).first << " : " << (*it).second << endl;
		it++;
	}
	cout << endl;

	//有const修饰
	lz::RBTree<int, int>::tree_reverse_const_iterator it1 = t1.rcbegin();
	while (it1 != t1.rcend())
	{
		//(*it1).second = 10;
		cout << (*it1).first << " : " << (*it1).second << endl;
		it1++;
	}
	cout << endl;

	for (auto e : t1)
	{
		e.second = 10;
		cout << e.first << " : " << e.second << endl;
	}
	cout << endl;
}

int main()
{
	Test5();

	return 0;
}

😎 😎 今天的内容到这里就结束了,希望各位小伙伴们能有所收获。
在这里插入图片描述

  • 11
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

今天也要写bug

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

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

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

打赏作者

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

抵扣说明:

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

余额充值