【C++】--- set和map的封装

一、set和map的类模板

1、在set中用K(key)来标识元素,

template < class Key>//set

2、map用K_Value(key value)。键值key通常用来排序和唯一标识元素, Value里面通常储存的是与key相关联的内容,只要找到了k就会找到其对应的value

因为键值key的类型 和 value的类型可能不同,况且在map的内部。
key 和 value 通过value_type这个类型绑定在一起,取名为:pair

注意: pair中的 key不能修改 但是value可以修改!(所以在key前面加一个 const)

typedef pair<const Key, T> value_type;
template < class Key, class T>//map

重点理解:

用红黑树来封装set和map的时候,set传给红黑树底层是 将 key传给底层的value,而map传给红黑树的是pair,给底层红黑树的value!

上层容器不同,那么底层红黑树的K T类型就不同:

在这里插入图片描述
在上层容器set中,K和T都代表着Key,底层红黑树节点中K和T储存的都是一样的:Key

但是在map中K就代表储存着Key,但是T就代表储存着:pair (key_value模型)

因为底层的红黑树,只能储存T,所以说,为了同时满足支持set和map要对 红黑树 进行改变。

二、红黑树节点的定义

1、红黑树的节点修改

把红黑树节点定义 由类模板

template<class K,class V>

修改为:

template<class T>

那么对节点 定义就变成了:

// 这里的 T就是上层set/map第2个形参 传来的类型
template<class T>
struct RBTreeNode
{
	RBTreeNode<T>* _left;
	RBTreeNode<T>* _right;
	RBTreeNode<T>* _parent;

	T _data;
	Colour _col;

	RBTreeNode(const T& data)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _data(data)
		, _col(RED)
	{

	}
};

由于红黑树不知道上层传的是K还是pair,这是由上层传递的模板参数T决定的,上层是封装我的map和set。

2、仿函数

(1)节点比较大小的时候存在的问题

仿函数的产生的原因:

在我们写插入Inert()进行比较的时候,set直接通过k可以进行比较,虽然map也可以比较,但

是他那个规则与我们所预期的不相符:

在这里插入图片描述
库里面关于map的比较是先first大小否相等,如果相等继续比较second。而我们所预期的是只比较first
一般不符合 “比较” 要求,就需要自己写一个 关于“比较” 的仿函数!

(2)回顾仿函数

仿函数让一个类的使用看上去像个函数。仿函数是在类中实现了一个operator( ),是一个类的对象,这个类就有了类似函数的行为,所以这个类就是一个仿函数类,目的是为了让函数拥有类的性质。

这个类的对象即仿函数,可以当作一般函数去用,只不过仿函数的功能是在一个类中的运算符operator()中实现的,使用的时候把函数作为参进行传递即可。

详细介绍见:【C++】—STL之priority_queue

Set有set的仿函数,map 有 map的反函数。这样的仿函数看起来没有用,但实际上的目的是让底层的红黑树分别获取 set的key和map的first

①set的仿函数:

namespace yjl
{
	template<class K>
	class set
	{
		//仿函数,获取set的key
		struct SetKeyOfT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};
    
    public:
		bool insert(const K& k)
		{
			_t.Insert(k);
			return true;
		}
 
	private:
		RBTree<K, K,SetKeyOfT> _t;
	};
}

②map的仿函数:

namespace yjl
{
	template<class K,class V>
	class map
	{
		//仿函数,获取map的first
		struct MapKeyOfT
		{
			const K& operator()(const pair<const K, V>& kv)
			{
				return kv.first;
			}
		};
 
    public:
        //插入
		bool insert(const pair<const K, V>& kv)
		{
			_t.Insert(kv);
			return true;
		}
	private:
		RBTree<K, pair<const K, V>, MapKeyOfT> _t;
	};
}

有了仿函数红黑树的类在实现时,就要在模板参数中增加KeyOfT仿函数。

(3)修改红黑树的定义

template<class K, class T, class KeyOfT>
class RBTree
{
	typedef RBTreeNode<T> Node;
	
private:
	Node* _root;
};

(4)修改红黑树的插入

	//插入
	pair<Node*, bool> Insert(const pair<K, V>& kv)
	{
		if (_root == nullptr)
		{
			_root = new Node(kv);
			_root->_col = BLACK;
			return make_pair(_root, true);
		}
 
		KeyOfT kot;
 
		//1.先看树中,kv是否存在
		Node* parent = nullptr;
		Node* cur = _root;
		while (cur)
		{
			if (kot(cur->_data) < kot(data))
			{
				//kv比当前节点值大,向右走
				parent = cur;
				cur = cur->_right;
			}
			else if (kot(cur->_data) > kot(data))
			{
				//kv比当前节点值小,向左走
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				//kv和当前节点值相等,已存在,插入失败
				return make_pair(cur, false);
			}
		}
 
		//2.走到这里,说明kv在树中不存在,需要插入kv,并且cur已经为空,parent已经是叶子节点了
		Node* newNode = new Node(kv);
		newNode->_col = RED;
		if (kot(parent->_data) < kot(data))
		{
			//kv比parent值大,插入到parent的右边
			parent->_right = newNode;
			newNode->_parent = parent;
		}
		else
		{
			//kv比parent值小,插入到parent的左边
			parent->_left = newNode;
			newNode->_parent = parent;
		}
		cur = newNode;
 
		//如果父亲存在,且父亲颜色为红就要处理
		while (parent && parent->_col == RED)
		{
			//情况一和情况二、三的区别关键看叔叔
			Node* grandfather = parent->_parent;//当父亲是红色时,根据规则(2)根节点一定是黑色,祖父一定存在
			if (parent == grandfather->_left)//父亲是祖父的左子树
			{
				Node* uncle = grandfather->_right;
				//情况一:叔叔存在且为红
				if (uncle->_col == RED)
				{
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;
 
					//继续向上调整
					cur = grandfather;
					parent = cur->_parent;
				}
				else//情况二+情况三:叔叔不存在或叔叔存在且为黑
				{
					//情况二:单旋
					if (cur == parent->_left)
					{
						RotateR(grandfather);
						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					else//情况三:双旋
					{
						RotateL(parent);
						RotateR(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}
					break;//插入结束
				}
			}
			else//父亲是祖父的右子树
			{
				Node* uncle = grandfather->_left;
				//情况一:叔叔存在且为红
				if (uncle && uncle->_col == RED)
				{
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;
 
					//继续往上调整
					cur = grandfather;
					parent = grandfather->_parent;
				}
				else//情况二+情况三:叔叔不存在或叔叔存在且为黑
				{
					//情况二:单旋
					if (cur == parent->_right)
					{
						RotateL(grandfather);
						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					else//情况三:双旋
					{
						RotateR(parent);
						RotateL(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}
					break;//插入结束
				}
			}
 
		}
		_root->_col = BLACK;
 
		return make_pair(newNode, true);
	}
 
	void RotateR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = nullptr;
 
		if (subL)
		{
			subLR = subL->_right;
		}
		//1.左子树的右子树变我的左子树
		parent->_left = subLR;
 
		if (subLR)
		{
			subLR->_parent = parent;
		}
 
		//左子树变父亲
		subL->_right = parent;
		Node* parentParent = parent->_parent;
		parent->_parent = subL;
 
 
		if (parent == _root)//parent是根
		{
			_root = subL;
			_root->_parent = nullptr;
		}
		else//parent不是根,是子树
		{
			if (parentParent->_left == parent)
			{
				//parent是自己父亲的左子树,将subL作为parent父亲的左孩子
				parentParent->_left = subL;
			}
			else
			{
				//parent是自己父亲的右子树,将subL作为parent父亲的右孩子
				parentParent->_right = subL;
			}
 
			//subL的父亲就是parent的父亲
			subL->_parent = parentParent;
		}
	}
 
	void RotateL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = nullptr;
 
		if (subR)
		{
			subRL = subR->_left;
		}
 
		//1.右子树的左子树变我的右子树
		parent->_right = subRL;
 
		if (subRL)
		{
			subRL->_parent = parent;
		}
 
		//2.右子树变父亲
		subR->_left = parent;
		Node* parentParent = parent->_parent;
		parent->_parent = subR;
 
		if (parent == _root)//parent是根
		{
			_root = parent;
			_root->_parent = nullptr;
		}
		else//parent不是根,是子树
		{
			if (parentParent->_left == parent)
			{
				//parent是自己父亲的左子树,将subR作为parent父亲的左孩子
				parentParent->_left = subR;
			}
			else
			{
				//parent是自己父亲的右子树,将subR作为parent父亲的右孩子
				parentParent->_right = subR;
			}
 
			//subR的父亲就是parent的父亲
			subR->_parent = parentParent;
		}
	}

(5)修改红黑树的查找

	//查找
	Node* Find(const K& key)
	{
		KeyOfT kot;
		Node* cur = _root;
		while (cur)
		{
			if (kot(cur->_data) < key)
			{
				cur = cur->_right;
			}
			else if (kot(cur->_data) > key)
			{
				cur = cur->_left;
			}
			else
			{
				return cur;
			}
		}
		return nullptr;//空树,直接返回
	}

三、红黑树迭代器

map和set的迭代器的实现其实本质上是红黑树迭代器的实现,迭代器的实现需要定义模板类型、模板类型引用、模板类型指针。

1、红黑树中迭代器重命名

在红黑树中重命名模板类型、模板类型引用、模板类型指针,定义为public,外部就能使用iterator了:

template<class K, class T, class KeyOfT>
class RBTree
{
	typedef RBTreeNode<T> Node;
 
public:
	typedef __TreeIterator<T, T&, T*> iterator;//模板类型、模板类型引用、模板类型指针
    
    //红黑树函数...
    
private:
	Node* _root;
};

2、正向迭代器的定义

红黑树的迭代器的本质是对节点指针进行封装,所以迭代器中只有封装红黑树节点指针这一个成员变量 。正向迭代器:

template<class T,class Ref,class ptr>
struct __TreeIterator
{
	typedef RBTreeNode<T> Node;
	typedef __TreeIterator<T, Ref, ptr> Self;
      
	Node* _node;//成员变量
	
};

3、迭代器构造

用节点指针构造正向迭代器:


	//构造函数
	__TreeIterator(Node* node)
		:_node(node)
	{}

4、正向迭代器重载*

Ref对正向迭代器解引用,返回节点数据引用:

	//* 解引用,返回节点数据
	Ref Operator*()
	{
		return _node->_data;
	}

5、正向迭代器重载->

Ptr对正向迭代器使用->,返回节点数据指针:

	//-> 返回节点数据地址
	Ptr Operator->()
	{
		return &_node->_data;
	}

6、正向迭代器重载==

判断节点是否相同 :

	//判断两个迭代器是否相同
	bool operator==(const Self& s)
	{
		return _node == s._node;//判断节点是否相同
	}

7、正向迭代器重载!=

判断节点是否不同

	//判断两个迭代器是否不同
	bool operator!=(const Self& s)
	{
		return _node != s._node;//判断节点是否不同
	}

8、正向迭代器++

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

	//红黑树迭代器的++也就是红黑树的++
	Self operator++()
	{
		//1.右子树不为空
		if (_node->_right)
		{
			//下一个访问的是右树的中序第一个节点(即右子树最左节点)。
			Node* left = _node->_right;
 
			//找最左节点
			while (left->_left)
			{
				left = left->_left;
			}
			_node = left;
		}
		else//2.右子树为空,下一个访问的就是当前节点的父亲
		{
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && cur == parent->_right)
			{
				cur = cur->_parent;
				parent = parent->_parent;
			}
			_node = parent;
		}
 
		return *this;
	}
};

9、正向迭代器- -

①当节点的左子树不为空时,++就要走到左子树的最右节点

②当节点的左子树为空时,++就要走到节点的父亲

	//红黑树迭代器的--也就是红黑树的--
	Self operator--()
	{
		//1.左子树不为空
		if (_node->_left)
		{
			//下一个访问的是左树的中序左后节点(即做子树最右节点)。
			Node* right = _node->_left;
 
			//找最右节点
			while (right->_right)
			{
				right = right->_right;
			}
			_node = right;
		}
		else//2.左子树为空,下一个访问的就是当前节点的父亲
		{
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && cur == parent->_left)
			{
				cur = cur->_parent;
				parent = parent->_parent;
			}
			_node = parent;
		}
 
		return *this;
	}

10、红黑树中实现迭代器

在迭代器中:实现begin( )找最左节点,end( )最后一个节点的下一个位置

注意:在迭代器中,这里的· end()一定指的是 右子树的最右结点的下一个节点,即:nullptr

template<class K, class T, class KeyOfT>
class RBTree
{
	typedef RBTreeNode<T> Node;
 
public:
	typedef __TreeIterator<T, T&, T*> iterator;//模板类型、模板类型引用、模板类型指针
    
    //找最左节点
	iterator begin()
	{
		Node* left = _root;
		while (left && left->_left)
		{
			left = left->_left;
		}
 
		return iterator(left)//返回最左节点的正向迭代器
	}
 
	//结束
	iterator end()
	{
		return iterator(nullptr);
	}
    
private:
	Node* _root;
};

四、set模拟实现

调用红黑树对应接口实现set,插入和查找函数返回值当中的节点指针改为迭代器:

#pragma once
#include "RBTree.h"
namespace yjl
{
	template<class K>
	class set
	{
		//仿函数,获取set的key
		struct SetKeyOfT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};
	public:
		typedef typename RBTree<K, K, SetKeyOfT>::iterator iterator;
		
		//迭代器开始
		iterator begin()
		{
			return _t.begin();
		}
 
		//迭代器结束
		iterator end()
		{
			return _t.end();
		}
 
		//插入函数
		pair<iterator,bool> insert(const K& key)
		{
			
			return _t.Insert(key);
		}
 
		//查找
		iterator find(const K& key)
		{
			return _t.find(key);
		}
	private:
		RBTree<K, K, SetKeyOfT> _t;
	};
}

五、map模拟实现

调用红黑树对应接口实现map,插入和查找函数返回值当中的节点指针改为迭代器,增加operator[ ]的重载:

#pragma once
#include "RBTree.h"
namespace yjl
{
	template<class K, class V>
	class map
	{
		//仿函数,获取map的first
		struct MapKeyOfT
		{
			const K& operator()(const pair<const K, V>& kv)
			{
				return kv.first;
			}
		};
	public:
		typedef typename RBTree<K, K, MapKeyOfT>::iterator iterator;
 
		//迭代器开始
		iterator begin()
		{
			return _t.begin();
		}
 
		//迭代器结束
		iterator end()
		{
			return _t.end();
		}
 
		//插入
		pair<iterator, bool> insert(const pair<const K, V>& kv)
		{
			return _t.Insert(kv);
		}
 
		//重载operator[]
		V& operator[](const K& key)
		{
			pair<iterator, bool> ret = insert(make_pair(key, V()));
			iterator it = ret.first;
			return it->second;
		}
 
		//查找
		iterator find(const K& key)
		{
			return _t.find(key);
		}
 
	private:
		RBTree<K, pair<const K, V>, MapKeyOfT> _t;
	};
}

六、红黑树完整代码段

#pragma once
#include<iostream>
using namespace std;
 
 
//节点颜色
enum Colour
{
	RED,
	BLACK,
};
 
//红黑树节点定义
template<class T>
struct RBTreeNode
{
	RBTreeNode<T>* _left;//节点的左孩子
	RBTreeNode<T>* _right;//节点的右孩子
	RBTreeNode<T>* _parent;//节点的父亲
 
	T _data;//节点的值
	Colour _col;//节点颜色
 
	RBTreeNode(const T& x)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _data(x)
		, _col(RED)
	{}
};
 
 
template<class T,class Ref,class ptr>
struct __TreeIterator
{
	typedef RBTreeNode<T> Node;
	typedef __TreeIterator<T, Ref, ptr> Self;
 
	Node* _node;
 
	//构造函数
	__TreeIterator(Node* node)
		:_node(node)
	{}
	
	//* 解引用,返回节点数据
	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;
	}
 
	//红黑树迭代器的++也就是红黑树的++
	Self operator++()
	{
		//1.右子树不为空
		if (_node->_right)
		{
			//下一个访问的是右树的中序第一个节点(即右子树最左节点)。
			Node* left = _node->_right;
 
			//找最左节点
			while (left->_left)
			{
				left = left->_left;
			}
			_node = left;
		}
		else//2.右子树为空,下一个访问的就是当前节点的父亲
		{
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && cur == parent->_right)
			{
				cur = cur->_parent;
				parent = parent->_parent;
			}
			_node = parent;
		}
 
		return *this;
	}
 
	//红黑树迭代器的--也就是红黑树的--
	Self operator--()
	{
		//1.左子树不为空
		if (_node->_left)
		{
			//下一个访问的是左树的中序左后节点(即做子树最右节点)。
			Node* right = _node->_left;
 
			//找最右节点
			while (right->_right)
			{
				right = right->_right;
			}
			_node = right;
		}
		else//2.左子树为空,下一个访问的就是当前节点的父亲
		{
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && cur == parent->_left)
			{
				cur = cur->_parent;
				parent = parent->_parent;
			}
			_node = parent;
		}
 
		return *this;
	}
 
 
};
 
//插入节点颜色是红色好,还是黑色好,红色
//因为插入红色节点,可能破坏规则3,影响不大
//插入黑色节点,一定破坏规则4 ,并且影响其他路径,影响很大
 
template<class K, class T, class KeyOfT>
class RBTree
{
	typedef RBTreeNode<T> Node;
public:
	typedef __TreeIterator<T, T&, T*> iterator;//模板类型、模板类型引用、模板类型指针
 
	//构造函数
	RBTree()
		:_root(nullpte)
	{}
 
	//析构
	~RBTree()
	{
		_Destroy(_root);
		_root = nullptr;
	}
 
	void _Destroy(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
		_Destroy(root->_left);
		_Destroy(root->_right);
		delete root;
	}
 
	//找最左节点
	iterator begin()
	{
		Node* left = _root;
		while (left && left->_left)
		{
			left = left->_left;
		}
 
		return iterator(left);//返回最左节点的正向迭代器
	}
 
	//结束
	iterator end()
	{
		return iterator(nullptr);
	}
 
	//构造函数
	RBTree()
		:_root(nullptr)
	{}
 
	void Destroy(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
 
		Destroy(root->_left);
		Destroy(root->_right);
	}
	~RBTree()
	{
		Destroy(_root);
		_root = nullptr;
	}
 
	//插入
	pair<Node*, bool> Insert(const T& data)
	{
		if (_root == nullptr)
		{
			_root = new Node(data);
			_root->_col = BLACK;
			return make_pair(_root, true);
		}
 
		KeyOfT kot;
 
		//1.先看树中,kv是否存在
		Node* parent = nullptr;
		Node* cur = _root;
		while (cur)
		{
			if (kot(cur->_data) < kot(data))
			{
				//kv比当前节点值大,向右走
				parent = cur;
				cur = cur->_right;
			}
			else if (kot(cur->_data) > kot(data))
			{
				//kv比当前节点值小,向左走
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				//kv和当前节点值相等,已存在,插入失败
				return make_pair(cur, false);
			}
		}
 
		//2.走到这里,说明kv在树中不存在,需要插入kv,并且cur已经为空,parent已经是叶子节点了
		Node* newNode = new Node(data);
		newNode->_col = RED;
		if (kot(parent->_data) < kot(data))
		{
			//kv比parent值大,插入到parent的右边
			parent->_right = newNode;
			newNode->_parent = parent;
		}
		else
		{
			//kv比parent值小,插入到parent的左边
			parent->_left = newNode;
			newNode->_parent = parent;
		}
		cur = newNode;
 
		//如果父亲存在,且父亲颜色为红就要处理
		while (parent && parent->_col == RED)
		{
			//情况一和情况二、三的区别关键看叔叔
			Node* grandfather = parent->_parent;//当父亲是红色时,根据规则(2)根节点一定是黑色,祖父一定存在
			if (parent == grandfather->_left)//父亲是祖父的左子树
			{
				Node* uncle = grandfather->_right;
				//情况一:叔叔存在且为红
				if (uncle->_col == RED)
				{
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;
 
					//继续向上调整
					cur = grandfather;
					parent = cur->_parent;
				}
				else//情况二+情况三:叔叔不存在或叔叔存在且为黑
				{
					//情况二:单旋
					if (cur == parent->_left)
					{
						RotateR(grandfather);
						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					else//情况三:双旋
					{
						RotateL(parent);
						RotateR(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}
					break;//插入结束
				}
			}
			else//父亲是祖父的右子树
			{
				Node* uncle = grandfather->_left;
				//情况一:叔叔存在且为红
				if (uncle && uncle->_col == RED)
				{
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;
 
					//继续往上调整
					cur = grandfather;
					parent = grandfather->_parent;
				}
				else//情况二+情况三:叔叔不存在或叔叔存在且为黑
				{
					//情况二:单旋
					if (cur == parent->_right)
					{
						RotateL(grandfather);
						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					else//情况三:双旋
					{
						RotateR(parent);
						RotateL(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}
					break;//插入结束
				}
			}
 
		}
		_root->_col = BLACK;
 
		return make_pair(newNode, true);
	}
 
	void RotateR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = nullptr;
 
		if (subL)
		{
			subLR = subL->_right;
		}
		//1.左子树的右子树变我的左子树
		parent->_left = subLR;
 
		if (subLR)
		{
			subLR->_parent = parent;
		}
 
		//左子树变父亲
		subL->_right = parent;
		Node* parentParent = parent->_parent;
		parent->_parent = subL;
 
 
		if (parent == _root)//parent是根
		{
			_root = subL;
			_root->_parent = nullptr;
		}
		else//parent不是根,是子树
		{
			if (parentParent->_left == parent)
			{
				//parent是自己父亲的左子树,将subL作为parent父亲的左孩子
				parentParent->_left = subL;
			}
			else
			{
				//parent是自己父亲的右子树,将subL作为parent父亲的右孩子
				parentParent->_right = subL;
			}
 
			//subL的父亲就是parent的父亲
			subL->_parent = parentParent;
		}
	}
 
	void RotateL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = nullptr;
 
		if (subR)
		{
			subRL = subR->_left;
		}
 
		//1.右子树的左子树变我的右子树
		parent->_right = subRL;
 
		if (subRL)
		{
			subRL->_parent = parent;
		}
 
		//2.右子树变父亲
		subR->_left = parent;
		Node* parentParent = parent->_parent;
		parent->_parent = subR;
 
		if (parent == _root)//parent是根
		{
			_root = parent;
			_root->_parent = nullptr;
		}
		else//parent不是根,是子树
		{
			if (parentParent->_left == parent)
			{
				//parent是自己父亲的左子树,将subR作为parent父亲的左孩子
				parentParent->_left = subR;
			}
			else
			{
				//parent是自己父亲的右子树,将subR作为parent父亲的右孩子
				parentParent->_right = subR;
			}
 
			//subR的父亲就是parent的父亲
			subR->_parent = parentParent;
		}
	}
 
	//查找
	Node* Find(const K& key)
	{
		KeyOfT kot;
		Node* cur = _root;
		while (cur)
		{
			if (kot(cur->_data) < key)
			{
				cur = cur->_right;
			}
			else if (kot(cur->_data) > key)
			{
				cur = cur->_left;
			}
			else
			{
				return cur;
			}
		}
		return nullptr;//空树,直接返回
	}
 
	bool _CheckBalance(Node* root, int blackNum, int count)
	{
		if (root == nullptr)
		{
			if (count != blackNum)
			{
				cout << "黑色节点数量不相等" << endl;
				return false;
			}
			return true;
		}
 
		if (root->_col == RED && root->_parent->_col == RED)
		{
			cout << "存在连续红色节点" << endl;
			return false;
		}
 
		if (root->_col == BLACK)
		{
			count++;
		}
 
		return _CheckBalance(root->_left, blackNum, count)
			&& _CheckBalance(root->_right, blackNum, count);
	}
 
	//检查是否平衡
	bool CheckBalance()
	{
		if (_root == nullptr)
		{
			return true;
		}
 
		if (_root->_col == RED)
		{
			cout << "根节点为红色" << endl;
			return false;
		}
 
		//找最左路径做黑色节点数量参考值
		int blackNum = 0;
		Node* left = _root;
		while (left)
		{
			if (left->_col == BLACK)
			{
				blackNum++;
			}
			left = left->_left;
		}
 
		int count = 0;
		return _CheckBalance(_root, blackNum, count);
	}
 
 
	//遍历
	void _InOrder(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
 
		_InOrder(root->_left);
		cout << root->_kv.first << ":" << root->_kv.second << endl;
		_InOrder(root->_right);
	}
 
	void InOrder()
	{
		_InOrder(_root);
		cout << endl;
	}
private:
	Node* _root;
};

测试代码:

#pragma once
#include "RBTree.h"
#include <vector>
#include <stdlib.h>
#include <time.h>
#include "Map.h"
#include "Set.h"
 
int main()
{
	yjl::map<int, int> m;
	m.insert(make_pair(1, 1));
	m.insert(make_pair(3, 3));
	m.insert(make_pair(0, 0));
	m.insert(make_pair(9, 9));
 
 
	yjl::set<int> s;
	s.insert(1);
	s.insert(5);
	s.insert(2);
	s.insert(1);
	s.insert(13);
	s.insert(0);
	s.insert(15);
	s.insert(18);
 
 
	yjl::set<int>::iterator sit = s.begin();
	while (sit != s.end())
	{
		cout << *sit << " ";
		++sit;
	}
	cout << endl;
 
 
	return 0;
}

七、注意事项、查缺补漏

1、关于STL容器迭代器end()的返回值

在这里插入图片描述

因为语法规定,只要是用STL容器:vector、list、stack、queue、deque、priority_queue、set、map等等,他们的迭代器中的end()返回值均是:nullptr

在这里插入图片描述

在这里插入图片描述

2、关于未实例化的类模板 前面要加 typename的原因

在这里插入图片描述
比如在 set 里面取出 RBTree 这个类里面的Iterator使用

在这里插入图片描述
在这里插入图片描述

3、要对map的K加const

因为map中pair的K能被修改,他的value可以被修改:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


好了,今天的分享就到这里了
如果对你有帮助,记得点赞👍+关注哦!
我的主页还有其他文章,欢迎学习指点。关注我,让我们一起学习,一起成长吧!

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小能软糖_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值