C++ 改造红黑树,封装map和set

avatar
作者
猴君
阅读量:3

C++ 改造红黑树,封装map和set

一.前言:已经实现好了的红黑树

set是Key模型的红黑树
map是Key-Value模型的红黑树
我们之前已经把红黑树实现并测试过了
这是Key-Value模型的红黑树
RBTree.h

#pragma once enum Color { 	RED, 	BLACK };  template<class K,class V> struct RBTreeNode { 	RBTreeNode<K,V>* _pLeft; 	RBTreeNode<K,V>* _pRight; 	RBTreeNode<K,V>* _pParent; 	Color _color; 	pair<K,V> _data; 	//新插入的节点默认是红色 	RBTreeNode(const pair<K,V>& data) 		:_pLeft(nullptr) 		,_pRight(nullptr) 		,_pParent(nullptr) 		,_color(RED) 		,_data(data) 	{} };  template<class K,class V> class RBTree { 	typedef RBTreeNode<K,V> Node; public:  	// 在红黑树中插入值为data的节点,插入成功返回true,否则返回false 	// 注意:为了简单起见,本次实现红黑树不存储重复性元素 	bool Insert(const pair<K,V>& data) 	{ 		if (_pRoot == nullptr) 		{ 			_pRoot = new Node(data); 			//根节点是黑色 			_pRoot->_color = BLACK; 			return true; 		} 		Node* cur = _pRoot, * parent = nullptr; 		while (cur) 		{ 			//比我小,往左找 			if (data.first < cur->_data.first) 			{ 				parent = cur; 				cur = cur->_pLeft; 			} 			//比我大,往右找 			else if (data.first > cur->_data.first) 			{ 				parent = cur; 				cur = cur->_pRight; 			} 			//有重复元素,插入失败 			else 			{ 				return false; 			} 		} 		//找到空位置,开始插入 		cur = new Node(data); 		//连接父亲和孩子 		if (cur->_data.first < parent->_data.first) 		{ 			parent->_pLeft = cur; 		} 		else 		{ 			parent->_pRight = cur; 		} 		cur->_pParent = parent; 		//父亲是黑色,插入成功 		if (parent->_color == BLACK) 		{ 			return true; 		} 		//父亲是红色,需要调整 		//且此时爷爷一定是黑色 		//根据叔叔的颜色来调整 		while (parent && parent->_color == RED) 		{ 			Node* grandParent = parent->_pParent; 			//爸爸是爷爷的左孩子 			if (parent == grandParent->_pLeft) 			{ 				Node* uncle = grandParent->_pRight; 				//根据叔叔的颜色来调整 				//1.叔叔存在且为红 				if (uncle && uncle->_color == RED) 				{ 					//修改爸爸,叔叔,爷爷的颜色 					uncle->_color = parent->_color = BLACK; 					grandParent->_color = RED; 					//此时视爷爷为新插入的红色节点继续向上影响 					cur = grandParent; 					parent = cur->_pParent; 				} 				//2.叔叔不存在或者叔叔是黑 				else 				{ 					//1.我是爸爸的左孩子 					if (parent->_pLeft == cur) 					{ 						//对爷爷进行一次右旋 						RotateR(grandParent); 						//把爷爷改成红色,爸爸改成黑色 						grandParent->_color = RED; 						parent->_color = BLACK; 						//此时爸爸是黑色,无需break,当然break也可以,因此爸爸是黑色,下次循环就不会进入了 					} 					//2.我是爸爸的右孩子 					else 					{ 						//1.对爸爸进行左旋 						RotateL(parent); 						//2.对爷爷右旋 						RotateR(grandParent); 						//3.孩子改成黑色,爷爷改成红色 						cur->_color = BLACK; 						grandParent->_color = RED; 						//4.一定要break,如果不break的话,因为爸爸是红色,所以循环会继续,此时就乱套了 						break; 					} 				} 			} 			//爸爸是爷爷的右孩子 			else 			{ 				Node* uncle = grandParent->_pLeft; 				//1.叔叔存在且为红 				if (uncle && uncle->_color == RED) 				{ 					uncle->_color = parent->_color = BLACK; 					grandParent->_color = RED; 					cur = grandParent; 					parent = cur->_pParent; 				} 				//2.叔叔不存在或者叔叔为黑 				else 				{ 					//1.我是爸爸的右孩子 					if (parent->_pRight == cur) 					{ 						//对爷爷左旋 						RotateL(grandParent); 						//爷爷改成红色,爸爸改成黑色 						grandParent->_color = RED; 						parent->_color = BLACK; 						//此时爸爸是黑色,无需break,当然break也可以,因此爸爸是黑色,下次循环就不会进入了 					} 					//2.我是爸爸的左孩子 					else 					{ 						//1.对爸爸右旋 						RotateR(parent); 						//2.对爷爷左旋 						RotateL(grandParent); 						//3.把孩子改成黑色,爷爷改成红色 						cur->_color = BLACK; 						grandParent->_color = RED; 						//4.一定要break,如果不break的话,因为爸爸是红色,所以循环会继续,此时就乱套了 						break; 					} 				} 			} 		} 		_pRoot->_color = BLACK; 		return true; 	}  	// 检测红黑树中是否存在关键字为key的节点,存在返回该节点的地址,否则返回nullptr 	Node* Find(const K& key) 	{ 		Node* cur = _pRoot; 		while (cur) 		{ 			if (cur->_data.first > key) 			{ 				cur = cur->_pLeft; 			} 			else if (cur->_data.second < key) 			{ 				cur = cur->_pRight; 			} 			else 			{ 				return cur; 			} 		} 		return nullptr; 	}  	// 检测红黑树是否为有效的红黑树,注意:其内部主要依靠_IsValidRBTRee函数检测 	bool IsValidRBTRee() 	{ 		//1.空树是红黑树 		if (_pRoot == nullptr) 		{ 			return true; 		} 		//2.根节点不能为红色 		if (_pRoot->_color == RED) 		{ 			return false; 		} 		//3.为了验证性质: 红黑树的任意一条路径上的黑色节点个数相同   找参考值 		size_t ReferenceCount = 0; 		Node* cur = _pRoot; 		while (cur) 		{ 			if (cur->_color == BLACK) 			{ 				ReferenceCount++; 			} 			cur = cur->_pLeft; 		} 		return _IsValidRBTRee(_pRoot, 0, ReferenceCount); 	}  	void InOrder() 	{ 		_InOrder(_pRoot); 	} private: 	bool _IsValidRBTRee(Node* pRoot, size_t blackCount, size_t& ReferenceCount) 	{ 		if (pRoot == nullptr) 		{ 			if (blackCount != ReferenceCount) 			{ 				cout << "存在黑色节点数量不相等的路径" << endl; 				return false; 			} 			return true; 		} 		//验证性质: 红黑树中不能存在连续的红色节点 		//如果一个节点是红色,该节点一定不是根节点,因此该节点一定有父亲 		//只需要保证红色节点的父亲不是红色节点即可 		if (pRoot->_color == RED) 		{ 			if (pRoot->_pParent->_color == RED) 			{ 				cout << "存在连续的红色节点" << endl; 				return false; 			} 		} 		else 		{ 			blackCount++; 		} 		return _IsValidRBTRee(pRoot->_pLeft, blackCount, ReferenceCount) && _IsValidRBTRee(pRoot->_pRight, blackCount, ReferenceCount); 	}  	// 右单旋 	void RotateR(Node* pParent) 	{ 		Node* subL = pParent->_pLeft; 		Node* subLR = subL->_pRight; 		Node* grandParent = pParent->_pParent; 		subL->_pRight = pParent; 		pParent->_pParent = subL; 		pParent->_pLeft = subLR; 		if (subLR) 			subLR->_pParent = pParent; 		if (grandParent == nullptr) 		{ 			_pRoot = subL; 			_pRoot->_pParent = nullptr; 		} 		else 		{ 			if (pParent == grandParent->_pLeft) 			{ 				grandParent->_pLeft = subL; 			} 			else 			{ 				grandParent->_pRight = subL; 			} 			subL->_pParent = grandParent; 		} 	}  	// 左单旋 	void RotateL(Node* pParent) 	{ 		Node* subR = pParent->_pRight; 		Node* subRL = subR->_pLeft; 		Node* grandParent = pParent->_pParent; 		pParent->_pParent = subR; 		subR->_pLeft = pParent; 		pParent->_pRight = subRL; 		if (subRL) 			subRL->_pParent = pParent; 		//说明此时pParent是_pRoot 		if (grandParent == nullptr) 		{ 			_pRoot = subR; 			_pRoot->_pParent = nullptr; 		} 		//说明此时pParent所在的树是一颗子树,需要跟父亲链接 		else 		{ 			if (pParent == grandParent->_pLeft) 			{ 				grandParent->_pLeft = subR; 			} 			else 			{ 				grandParent->_pRight = subR; 			} 			subR->_pParent = grandParent; 		} 	}  	void _InOrder(Node* root) 	{ 		if (root == nullptr) return; 		_InOrder(root->_pLeft); 		cout << root->_data.first << " " << root->_data.second << " "; 		_InOrder(root->_pRight); 	} private: 	Node* _pRoot = nullptr; }; 

要想用红黑树来封装set和map,我们首先想到的是在搞一份Key模型的红黑树,
然后用Key模型红黑树来封装set,Key-Value模型红黑树封装map
但是STL库中set和map的设计却不是这样的
它们都是只用了一份红黑树,怎么做到的呢?
下面就让我们来探索一下

二.简化STL库里面对于map和set的封装

红黑树的源码:是一个KV模型的红黑树
它是通过传入的Value的值来判断类型,利用模板的技术实现的一棵泛型的红黑树
通过模板的实例化,实现了map和set

1.STL库中红黑树的简化代码

我们挑选出一部分很重要的成员来看看STL库中的红黑树是怎么个泛型法呢?
在这里插入图片描述

2.STL库中set的简化代码

下面我们看一下set
在这里插入图片描述

3.STL库中map的简化代码

下面我们看一下map
在这里插入图片描述

4.封装map和set的第一步

在这里插入图片描述
RBTree.h

template<class K, class V> class RBTree 

对于V这个模板参数:
可能是键值Key,也可能是由Key和Value共同组成的键值对pair

MySet.h
对于set而言,传入底层红黑树的模板参数就是Key和Key

template<class K> class set { private: 	RBTree<K, K> _root; }; 

MyMap.h
对于map而言,传入底层红黑树的模板参数就是Key和pair<const Key,Value>

template<class K, class V> class map { private: 	//我们知道:map的Key不允许被修改,Value允许被修改 	//因此pair里面的K加上const修饰 	RBTree<K, pair<const K, V>> _root; }; 

5.红黑树第一个模板参数的价值

通过上面的传参,我们可以知道:
只需要对于红黑树的第二个模板参数传入不同的值就可以对set和map进行很好地区分
那么红黑树的第一个模板参数是不是就没有用了呢?

对于insert(const Value& v)来说,是这样的,因为插入的值就是value
set的value是key,map的value是pair

但是对于find(const Key& k)来说,查找的依据是key,对于set是可以的
但是对于map来说,它的value是一个键值对,而我们是需要key来查找的,因此第一个模板参数不能不要

6.红黑树节点的定义

在这里插入图片描述

enum Color { 	RED, 	BLACK }; template<class T> struct RBTreeNode { 	RBTreeNode<T>* _pLeft; 	RBTreeNode<T>* _pRight; 	RBTreeNode<T>* _pParent; 	Color _color; 	T _data; 	//新插入的节点默认是红色 	RBTreeNode(const T& data) 		:_pLeft(nullptr) 		, _pRight(nullptr) 		, _pParent(nullptr) 		, _color(RED) 		, _data(data) 	{} }; 

三.仿函数

1.解除仿函数的误解

在学习优先级队列的时候我们遇到了仿函数
当时我们写了一个greater的仿函数,传入greater就能建小堆
传入less就能建大堆

当时我们知道:仿函数是一个类,主要重载operator()
不过仿函数不仅仅可以用于比较大小,这是我们常有的一大误解

2.仿函数在这里的价值

由于红黑树不知道传的是set还是map
因此在insert时进行节点键值的比较时,底层红黑树需要使用仿函数来获取键值key,从而才能进行比较

3.set的仿函数

对set而言,仿函数就是返回Key

template<class K> class set { public: 	struct SetKeyofT 	{ 		const K& operator()(const K& k) 		{ 			return k; 		} 	}; private: 	RBTree<K, K,SetKeyofT> _root; }; 

4.map的仿函数

对map而言,仿函数就是返回pair的first,也就是Key

template<class K, class V> class map { public: 	struct MapKeyofT 	{ 		const K& operator()(const pair<const K, V>& kv) 		{ 			return kv.first; 		} 	}; private: 	//我们知道:map的Key不允许被修改,Value允许被修改 	//因此pair里面的K加上const修饰 	RBTree<K, pair<const K, V>,MapKeyofT> _root; }; 

5.红黑树的修改

修改之后,因为红黑树的代码太长了,所以这里只列出修改的地方
1.类模板

template<class K, class V,class KeyofT> 

2.成员变量

private: 		Node* _pRoot = nullptr; 		KeyofT _kot; 

3.insert插入时的比较逻辑

//1 参数只需要传V即可(也就是红黑树的第二个模板参数) //对于set而言V就是Key //对于map而言,V就是pair<K,V> bool Insert(const V& data) { 	if (_pRoot == nullptr) 	{ 		_pRoot = new Node(data); 		//根节点是黑色 		_pRoot->_color = BLACK; 		return true; 	} 	Node* cur = _pRoot, * parent = nullptr; 	while (cur) 	{ 		//比我小,往左找 		if (_kot(data) < _kot(cur->_data)) 		{ 			parent = cur; 			cur = cur->_pLeft; 		} 		//比我大,往右找 		else if (_kot(data) > _kot(cur->_data)) 		{ 			parent = cur; 			cur = cur->_pRight; 		} 		//有重复元素,插入失败 		else 		{ 			return false; 		} 	} 	//找到空位置,开始插入 	cur = new Node(data); 	//连接父亲和孩子 	if (_kot(cur->_data) < _kot(parent->_data)) 	{ 		parent->_pLeft = cur; 	} 	//..旋转变色等其他操作,这些操作都无需进行节点的Key有关比较 } 

在这里插入图片描述

6.仿函数小总结

在这里插入图片描述

四.迭代器

1.迭代器类的定义

跟list类似,红黑树的正向迭代器也是对节点指针进行了一层封装
同样的,为了实现const_iterator,这里传入Ref和Ptr这两个模板参数

不过这里增加了const迭代器和非const迭代器的转化

template<class T, class Ref, class Ptr> struct __TreeIterator { 	typedef RBTreeNode<T> Node; 	typedef __TreeIterator<T, T&, T*> iterator; 	typedef __TreeIterator<T, Ref, Ptr> Self; 	Node* _node;  	__TreeIterator(Node* node) 		:_node(node) 	{}  	//普通迭代器和const_iterator的转化 	__TreeIterator(const iterator& it) 		:_node(it._node) 	{} 	 	Ref operator*();  	Ptr operator->();  	//找中序遍历的下一个节点 	Self& operator++();  	bool operator!=(const Self& s);  	bool operator==(const Self& s); }; 

2.解引用,!=,==的实现

Ref operator*() { 	return _node->_data; }  Ptr operator->() { 	return &_node->_data; }  bool operator!=(const Self& s) { 	return _node != s._node; }  bool operator==(const Self& s) { 	return _node == s._node; } 

3.operator++

这里的迭代器走的是二叉树的中序遍历,因此++要找到中序遍历的下一个节点
如何找呢?
1.如果节点的右子树不为空,中序的下一个节点就是右子树的最左节点
2.如果节点的右子树为空,那么就需要一直往上找
直到父亲为空或者孩子是父亲的左孩子时,此时的父亲就是中序的下一个节点

//找中序遍历的下一个节点 Self& operator++() { 	//1.左子树 根节点 右子树 	//如果有右孩子,那就是右子树的最左节点 	//如果没有右孩子,那往上找直到我是父亲的左孩子或者我的父亲是空节点为止,此时我的父亲就是下一个节点 	Node* cur = _node; 	if (cur->_pRight) 	{ 		Node* right = cur->_pRight; 		while (right->_pLeft) 		{ 			right = right->_pLeft; 		} 		_node = right; 	} 	else 	{ 		Node* parent = cur->_pParent; 		while (parent && parent->_pRight == cur) 		{ 			cur = parent; 			parent = cur->_pParent; 		} 		_node = parent; 	} 	return *this; } 

4.给红黑树加上begin和end

begin是中序的第一个节点,也就是最左节点
end是中序的最后一个节点的下一个节点,也就是空节点

跟list一样,普通迭代器就是V V& V*
const_iterator就是V const V& const V*

template<class K, class V,class KeyofT> class RBTree { 	typedef RBTreeNode<V> Node; public:  	typedef __TreeIterator<V, V&, V*> iterator;  	typedef __TreeIterator<V,const V&,const V*> const_iterator;  	iterator begin() 	{ 		Node* cur = _pRoot; 		while (cur && cur->_pLeft) 		{ 			cur = cur->_pLeft; 		} 		return iterator(cur); 	}  	iterator end() 	{ 		return iterator(nullptr); 	}  	const_iterator begin() const 	{ 		Node* cur = _pRoot; 		while (cur && cur->_pLeft) 		{ 			cur = cur->_pLeft; 		} 		return const_iterator(cur); 	}  	const_iterator end() const 	{ 		return const_iterator(nullptr); 	} 	//其他成员.... }; 

五.set的实现

1.注意

1.typename

直接复用红黑树的接口即可实现set
注意:

typedef typename RBTree<K, K, SetKeyofT>::const_iterator iterator; 

typename的作用:因为没有实例化的模板是区分不了静态变量和类型的,因此需要我们使用typename告诉编译器这是类型

2.set的特性

库里面的set是不允许修改里面的值的
也就是说set的普通迭代器和const迭代器其实都是const迭代器
因此都复用红黑树的const_iterator即可

2.set的代码

namespace wzs { 	template<class K> 	class set 	{ 	public: 		struct SetKeyofT 		{ 			const K& operator()(const K& k) 			{ 				return k; 			} 		}; 		typedef typename RBTree<K, K, SetKeyofT>::const_iterator iterator;  		typedef typename RBTree<K, K, SetKeyofT>::const_iterator const_iterator;  		iterator begin() const 		{ 			return _root.begin(); 		} 		iterator end() const 		{ 			return _root.end(); 		} 		pair<iterator, bool> insert(const K& k) 		{ 			return _root.Insert(k); 		} 	private: 		RBTree<K, K, SetKeyofT> _root; 	}; } 

六.map的实现

1.operator[]的说明

STL库里面的map容器的方括号[]的作用:

返回值: 插入成功:pair<新插入的key所在的节点的iterator,true> 插入失败:pair<已经存在的key所在的节点的iterator,false>  作用: 如果插入成功,那么operator[]相当于insert 如果插入失败,那么operator[]相当于find  也就是说operator[]有多重技能 operator[]是map的一个非常重要的函数,可以实现3个功能:插入,查找,修改 

这是对源码的一个简化:

operator[]:给一个key,返回这个key所对应的value的引用 简化前: mapped_type& operator[](const Key_type& k) {    return (*(this->insert(make_pair(k,mapped_type())))).first).second; }  简化后 V& operator(const K& key) {    pair<iterator,bool> ret=insert(key,V());//V():value的默认构造的匿名对象    return ret.first->second; 

2.map的代码

namespace wzs { 	template<class K, class V> 	class map 	{ 	public: 		struct MapKeyofT 		{ 			const K& operator()(const pair<const K, V>& kv) 			{ 				return kv.first; 			} 		}; 		typedef typename RBTree<K, pair<const K, V>, MapKeyofT>::iterator iterator; 		typedef typename RBTree<K, pair<const K, V>, MapKeyofT>::const_iterator const_iterator; 		iterator begin() 		{ 			return _root.begin(); 		} 		iterator end() 		{ 			return _root.end(); 		}  		const_iterator begin() const 		{ 			return _root.begin(); 		} 		 		const_iterator end() const 		{ 			return _root.end(); 		}  		pair<iterator, bool> insert(const pair<const K, V>& kv) 		{ 			return _root.Insert(kv); 		} 		/* 			operator[]:给一个key,返回这个key所对应的value的引用 			简化前: 			mapped_type& operator[](const Key_type& k) 			{ 			   return (*(this->insert(make_pair(k,mapped_type())))).first).second; 			}  			简化后 			V& operator(const K& key) 			{ 			   pair<iterator,bool> ret=insert(key,V());//V():value的默认构造的匿名对象 			   return ret.first->second; 			} 		*/ 		V& operator[](const K& k) 		{ 			pair<iterator, bool> ret = insert(make_pair(k, V())); 			return ret.first->second; 		}  	private: 		//我们知道:map的Key不允许被修改,Value允许被修改 		//因此pair里面的K加上const修饰 		RBTree<K, pair<const K, V>, MapKeyofT> _root; 	}; } 

七.改造后的红黑树代码

#pragma once namespace wzs { 	enum Color 	{ 		RED, 		BLACK 	}; 	template<class T> 	struct RBTreeNode 	{ 		RBTreeNode<T>* _pLeft; 		RBTreeNode<T>* _pRight; 		RBTreeNode<T>* _pParent; 		Color _color; 		T _data; 		//新插入的节点默认是红色 		RBTreeNode(const T& data) 			:_pLeft(nullptr) 			, _pRight(nullptr) 			, _pParent(nullptr) 			, _color(RED) 			, _data(data) 		{} 	};  	//给红黑树增加迭代器 	template<class T, class Ref, class Ptr> 	struct __TreeIterator 	{ 		typedef RBTreeNode<T> Node; 		typedef __TreeIterator<T, T&, T*> iterator; 		typedef __TreeIterator<T, Ref, Ptr> Self; 		Node* _node;  		__TreeIterator(Node* node) 			:_node(node) 		{}  		//const迭代器和普通迭代器的转化 		__TreeIterator(const iterator& it) 			:_node(it._node) 		{}  		Ref operator*() 		{ 			return _node->_data; 		}  		Ptr operator->() 		{ 			return &_node->_data; 		}  		//找中序遍历的下一个节点 		Self& operator++() 		{ 			//1.左子树 根节点 右子树 			//如果有右孩子,那就是右子树的最左节点 			//如果没有右孩子,那往上找直到我是父亲的左孩子或者我的父亲是空节点为止,此时我的父亲就是下一个节点 			Node* cur = _node; 			if (cur->_pRight) 			{ 				Node* right = cur->_pRight; 				while (right->_pLeft) 				{ 					right = right->_pLeft; 				} 				_node = right; 			} 			else 			{ 				Node* parent = cur->_pParent; 				while (parent && parent->_pRight == cur) 				{ 					cur = parent; 					parent = cur->_pParent; 				} 				_node = parent; 			} 			return *this; 		}  		bool operator!=(const Self& s) 		{ 			return _node != s._node; 		}  		bool operator==(const Self& s) 		{ 			return _node == s._node; 		} 	};  	template<class K, class V,class KeyofT> 	class RBTree 	{ 		typedef RBTreeNode<V> Node; 	public: 		typedef __TreeIterator<V, V&, V*> iterator; 		typedef __TreeIterator<V, const V&, const V*> const_iterator;  		iterator begin() 		{ 			Node* cur = _pRoot; 			while (cur && cur->_pLeft) 			{ 				cur = cur->_pLeft; 			} 			return iterator(cur); 		}  		iterator end() 		{ 			return iterator(nullptr); 		}  		const_iterator begin() const 		{ 			Node* cur = _pRoot; 			while (cur && cur->_pLeft) 			{ 				cur = cur->_pLeft; 			} 			return const_iterator(cur); 		}  		const_iterator end() const 		{ 			return const_iterator(nullptr); 		}  		//1,参数只需要传V即可(也就是红黑树的第二个模板参数) 		//对于set而言V就是Key 		//对于map而言,V就是pair<K,V> 		pair<iterator, bool> Insert(const V& data) 		{ 			if (_pRoot == nullptr) 			{ 				_pRoot = new Node(data); 				//根节点是黑色 				_pRoot->_color = BLACK; 				return make_pair(iterator(_pRoot), true); 			} 			Node* cur = _pRoot, * parent = nullptr; 			while (cur) 			{ 				//比我小,往左找 				if (_kot(data) < _kot(cur->_data)) 				{ 					parent = cur; 					cur = cur->_pLeft; 				} 				//比我大,往右找 				else if (_kot(data) > _kot(cur->_data)) 				{ 					parent = cur; 					cur = cur->_pRight; 				} 				//有重复元素,插入失败 				else 				{ 					return make_pair(iterator(cur), false); 				} 			} 			//找到空位置,开始插入 			cur = new Node(data); 			Node* newnode = cur; 			//连接父亲和孩子 			if (_kot(cur->_data) < _kot(parent->_data)) 			{ 				parent->_pLeft = cur; 			} 			else 			{ 				parent->_pRight = cur; 			} 			cur->_pParent = parent; 			//父亲是黑色,插入成功 			if (parent->_color == BLACK) 			{ 				return make_pair(iterator(newnode), true); 			} 			//父亲是红色,需要调整 			//且此时爷爷一定是黑色 			//根据叔叔的颜色来调整 			while (parent && parent->_color == RED) 			{ 				Node* grandParent = parent->_pParent; 				//爸爸是爷爷的左孩子 				if (parent == grandParent->_pLeft) 				{ 					Node* uncle = grandParent->_pRight; 					//根据叔叔的颜色来调整 					//1.叔叔存在且为红 					if (uncle && uncle->_color == RED) 					{ 						//修改爸爸,叔叔,爷爷的颜色 						uncle->_color = parent->_color = BLACK; 						grandParent->_color = RED; 						//此时视爷爷为新插入的红色节点继续向上影响 						cur = grandParent; 						parent = cur->_pParent; 					} 					//2.叔叔不存在或者叔叔是黑 					else 					{ 						//1.我是爸爸的左孩子 						if (parent->_pLeft == cur) 						{ 							//对爷爷进行一次右旋 							RotateR(grandParent); 							//把爷爷改成红色,爸爸改成黑色 							grandParent->_color = RED; 							parent->_color = BLACK; 							//此时爸爸是黑色,无需break,当然break也可以,因此爸爸是黑色,下次循环就不会进入了 						} 						//2.我是爸爸的右孩子 						else 						{ 							//1.对爸爸进行左旋 							RotateL(parent); 							//2.对爷爷右旋 							RotateR(grandParent); 							//3.孩子改成黑色,爷爷改成红色 							cur->_color = BLACK; 							grandParent->_color = RED; 							//4.一定要break,如果不break的话,因为爸爸是红色,所以循环会继续,此时就乱套了 							break; 						} 					} 				} 				//爸爸是爷爷的右孩子 				else 				{ 					Node* uncle = grandParent->_pLeft; 					//1.叔叔存在且为红 					if (uncle && uncle->_color == RED) 					{ 						uncle->_color = parent->_color = BLACK; 						grandParent->_color = RED; 						cur = grandParent; 						parent = cur->_pParent; 					} 					//2.叔叔不存在或者叔叔为黑 					else 					{ 						//1.我是爸爸的右孩子 						if (parent->_pRight == cur) 						{ 							//对爷爷左旋 							RotateL(grandParent); 							//爷爷改成红色,爸爸改成黑色 							grandParent->_color = RED; 							parent->_color = BLACK; 							//此时爸爸是黑色,无需break,当然break也可以,因此爸爸是黑色,下次循环就不会进入了 						} 						//2.我是爸爸的左孩子 						else 						{ 							//1.对爸爸右旋 							RotateR(parent); 							//2.对爷爷左旋 							RotateL(grandParent); 							//3.把孩子改成黑色,爷爷改成红色 							cur->_color = BLACK; 							grandParent->_color = RED; 							//4.一定要break,如果不break的话,因为爸爸是红色,所以循环会继续,此时就乱套了 							break; 						} 					} 				} 			} 			_pRoot->_color = BLACK; 			return  make_pair(iterator(newnode), true); 		}  		// 检测红黑树中是否存在关键字为key的节点,存在返回该节点的地址,否则返回nullptr 		Node* Find(const K& key) 		{ 			Node* cur = _pRoot; 			while (cur) 			{ 				if (cur->_data.first > key) 				{ 					cur = cur->_pLeft; 				} 				else if (cur->_data.second < key) 				{ 					cur = cur->_pRight; 				} 				else 				{ 					return cur; 				} 			} 			return nullptr; 		}  		// 检测红黑树是否为有效的红黑树,注意:其内部主要依靠_IsValidRBTRee函数检测 		bool IsValidRBTRee() 		{ 			//1.空树是红黑树 			if (_pRoot == nullptr) 			{ 				return true; 			} 			//2.根节点不能为红色 			if (_pRoot->_color == RED) 			{ 				return false; 			} 			//3.为了验证性质: 红黑树的任意一条路径上的黑色节点个数相同   找参考值 			size_t ReferenceCount = 0; 			Node* cur = _pRoot; 			while (cur) 			{ 				if (cur->_color == BLACK) 				{ 					ReferenceCount++; 				} 				cur = cur->_pLeft; 			} 			return _IsValidRBTRee(_pRoot, 0, ReferenceCount); 		}  		void InOrder() 		{ 			_InOrder(_pRoot); 		} 	private: 		bool _IsValidRBTRee(Node* pRoot, size_t blackCount, size_t& ReferenceCount) 		{ 			if (pRoot == nullptr) 			{ 				if (blackCount != ReferenceCount) 				{ 					cout << "存在黑色节点数量不相等的路径" << endl; 					return false; 				} 				return true; 			} 			//验证性质: 红黑树中不能存在连续的红色节点 			//如果一个节点是红色,该节点一定不是根节点,因此该节点一定有父亲 			//只需要保证红色节点的父亲不是红色节点即可 			if (pRoot->_color == RED) 			{ 				if (pRoot->_pParent->_color == RED) 				{ 					cout << "存在连续的红色节点" << endl; 					return false; 				} 			} 			else 			{ 				blackCount++; 			} 			return _IsValidRBTRee(pRoot->_pLeft, blackCount, ReferenceCount) && _IsValidRBTRee(pRoot->_pRight, blackCount, ReferenceCount); 		}  		// 右单旋 		void RotateR(Node* pParent) 		{ 			Node* subL = pParent->_pLeft; 			Node* subLR = subL->_pRight; 			Node* grandParent = pParent->_pParent; 			subL->_pRight = pParent; 			pParent->_pParent = subL; 			pParent->_pLeft = subLR; 			if (subLR) 				subLR->_pParent = pParent; 			if (grandParent == nullptr) 			{ 				_pRoot = subL; 				_pRoot->_pParent = nullptr; 			} 			else 			{ 				if (pParent == grandParent->_pLeft) 				{ 					grandParent->_pLeft = subL; 				} 				else 				{ 					grandParent->_pRight = subL; 				} 				subL->_pParent = grandParent; 			} 		}  		// 左单旋 		void RotateL(Node* pParent) 		{ 			Node* subR = pParent->_pRight; 			Node* subRL = subR->_pLeft; 			Node* grandParent = pParent->_pParent; 			pParent->_pParent = subR; 			subR->_pLeft = pParent; 			pParent->_pRight = subRL; 			if (subRL) 				subRL->_pParent = pParent; 			//说明此时pParent是_pRoot 			if (grandParent == nullptr) 			{ 				_pRoot = subR; 				_pRoot->_pParent = nullptr; 			} 			//说明此时pParent所在的树是一颗子树,需要跟父亲链接 			else 			{ 				if (pParent == grandParent->_pLeft) 				{ 					grandParent->_pLeft = subR; 				} 				else 				{ 					grandParent->_pRight = subR; 				} 				subR->_pParent = grandParent; 			} 		}  		void _InOrder(Node* root) 		{ 			if (root == nullptr) return; 			_InOrder(root->_pLeft); 			cout << root->_data.first << " " << root->_data.second << " "; 			_InOrder(root->_pRight); 		} 	private: 		Node* _pRoot = nullptr; 		KeyofT _kot; 	}; } 

测试代码:

#include <iostream> using namespace std; #include <vector> #include "MySet.h" #include "MyMap.h" namespace wzs { 	void test1() 	{ 		map<int, int> m; 		m.insert(make_pair(1, 1)); 		m.insert(make_pair(2, 1)); 		m.insert(make_pair(3, 1323)); 		m.insert(make_pair(4, 111)); 		m.insert(make_pair(3, 12)); 		m.insert(make_pair(1, 1)); 		map<int, int>::iterator it = m.begin(); 		while(it != m.end()) 		{ 			it->second = 10; 			cout << it->first << " : " << it->second << endl; 			++it; 		} 		cout << endl; 		map<int, int>::const_iterator cit = m.begin(); 		while (cit != m.end()) 		{ 			//it->first = 10; 			//cit->second = 10; 			cout << cit->first << " : " << cit->second << endl; 			++cit; 		} 	}  	void test2() 	{ 		set<int> s; 		s.insert(1); 		s.insert(2); 		s.insert(3); 		s.insert(4); 		set<int>::iterator it = s.begin(); 		while (it != s.end()) 		{ 			//*it += 1; 			cout << *it << " "; 			++it; 		} 		cout << endl;  		set<int>::const_iterator cit = s.begin(); 		while (cit != s.end()) 		{ 			//*cit += 1; 			cout << *cit << " "; 			++cit; 		} 		cout << endl; 	}  	void test3() 	{ 		//统计次数 		map<string, int> countMap; 		vector<string> dict = { "hello","hi","who","hi","hi","who","which" }; 		for (auto& e : dict) 		{ 			countMap[e]++; 		} 		for (auto& e : countMap) 		{ 			cout << e.first << ":" << e.second << endl; 		} 	} } int main() { 	wzs::test1(); 	cout << endl; 	wzs::test2(); 	cout << endl; 	wzs::test3(); 	return 0; } 

在这里插入图片描述

以上就是C++ 改造红黑树,封装map和set的全部内容,希望能对大家有所帮助!

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!