C++------map和set的模拟实现



前言

在之前的讲解中我们了解到了关于set和map的简单使用set和map的模拟使用,本次我们来基于上节课的模拟实现的红黑树来对对map和set进行模拟实现!!!


正文开始

一、红黑树模拟实现STL中的map与set

首先我们先来看看STL库中是如何实现map和set的
在这里插入图片描述
我们在来看看库里面的红黑树是如何实现的
在这里插入图片描述

红黑树底层并不知道你给我传过来的参数是什么并不知道!(并不知道你是set还是map

set—>rb_tree<K,K>
map–>rb_tree<K,pair<K,V>>

大家可能会觉得对于set传入两个参数可能会有点浪费,但是没办法,因为红黑树还要去兼容map这个数据结构。
所以到底是set和map是由红黑树的第二个模板参数决定的!!!

这里会有人说了,那这第一个模板参数是不是就没有用了?

因为我们要用尽量少的资源去实现更多的资源,我们在这里用一颗红黑树去同时实现了set和map!!!
这里和迭代器的实现也有关系!

1.1 红黑树的迭代器

迭代器的好处是可以方便遍历,是数据结构的底层实现与用户透明。如果想要给红黑树增加迭代
器,需要考虑以前问题:

  • begin()与end()

STL明确规定,begin()与end()代表的是一段前闭后开的区间,而对红黑树进行中序遍历后,可以得到一个有序的序列,因此:begin()可以放在红黑树中最小节点(即最左侧节点)的位置,end()放在最大节点(最右侧节点)的下一个位置

在这里插入图片描述
end()我们定义为nullptr;
我们的实现简化了这一块

  • operator++()与operator–()
    对于operator++我们要的就是该树的中序遍历的下一个节点,就是我迭代器++的位置
    那我们如何找中序的下一个位置呢?

首先判断右子树是否为空
1.如果为空,要找该节点是祖先的左节点的祖先节点
2.非空–>右子树的最左节点

Self& operator++()
	{
		if (_node->_right == nullptr)
		{
			//找该节点是祖先的左节点的祖先节点
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent&& parent->_right==cur)
			{
				cur = cur->_parent;
				parent = parent->_parent;
			}
			_node = parent;
		}
		else
		{
			//右子树的最左节点
			Node* subLeft = _node->_right;
			while (subLeft->_left)
			{
				subLeft = subLeft->_left;
			}
			_node = subLeft;
		}
		return *this;
	}

对于operator–我们要的就是该树的中序遍历的上一个节点,就是我迭代器–的位置
那我们如何找中序的下一个位置呢?

首先判断左子树是否为空
1.如果为空,要找该节点是祖先的右节点的祖先节点
2.非空–>左子树的最右节点

Self& operator--()
	{
		if (_node->_left == nullptr)
		{
			//找该节点是祖先的右节点的祖先节点
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent&&parent->_left == cur)
			{
				cur = cur->_parent;
				parent = parent->_parent;
			}
			_node = parent;
		}
		else
		{
			//找左子树的最右节点
			Node* subRight = _node->_left;
			while (subRight->_right)
			{
				subRight = subRight->_right;
			}
			_node = subRight;
		}
	}

1.2 改造红黑树

因为关联式容器中存储的是<key, value>的键值对,因此
k为key的类型,
ValueType: 如果是map,则为pair<K, V>; 如果是set,则为k
KeyOfValue: 通过value来获取key的一个仿函数类

//T决定红黑树存什么数据
//set RBTree<K,K>
//map RBTree<K,pair<K,T>

//KeyOfT判断传进来的参数是K还是T
template<class K, class T,class KeyOfT>
class RBTree
{
	typedef RBTreeNode<T> Node;
public:
	typedef __RBTreeIterator<T, T&,T*> iterator;
	typedef __RBTreeIterator<T, const T&,const T*> const_iterator;

	iterator Begin()
	{
		Node* subLeft = _root;
		while (subLeft && subLeft->_left)
		{
			subLeft = subLeft->_left;
		}
		return iterator(subLeft);
	}
	iterator End()
	{
		return iterator(nullptr);
	}
	const_iterator Begin()const
	{
		Node* subLeft = _root;
		while (subLeft && subLeft->_left)
		{
			subLeft = subLeft->_left;
		}
		return const_iterator(subLeft);
	}
	const_iterator End()const
	{
		return const_iterator(nullptr);
	}


	pair<iterator,bool> insert(const T& data)
	{
		//1.搜索树的规则插入
		//2.看是否违反平衡规则,如果违反就需要处理:旋转
		if (_root == nullptr)
		{
			_root = new Node(data);
			_root->_col = BLACK;
			return make_pair(iterator(_root), true);
		}
		KeyOfT kot;
		Node* parent = nullptr;
		Node* cur = _root;
		while (cur)
		{
			if (kot(cur->_data) > kot(data))
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (kot(cur->_data) < kot(data))
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				return make_pair(iterator(cur), false);
			}
		}
		cur = new Node(data);
		Node* newNode = cur;
		cur->_col = RED;
		if (kot(parent->_data) > kot(data))
		{
			parent->_left = cur;
		}
		else
		{
			parent->_right = cur;
		}
		cur->_parent = parent;

		//调节关键看叔叔
		//存在连续的红色节点,违反规则三,需要处理
		while (parent && parent->_col == RED)
		{
			Node* grandfather = parent->_parent;
			if (grandfather->_left == parent)
			{
				Node* uncle = grandfather->_right;
				//情况一:
				if (uncle && uncle->_col == RED)//叔叔存在且为红
				{
					//变色
					parent->_col = BLACK;
					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 = BLACK;
					uncle->_col = BLACK;
					grandfather->_col = RED;
					//继续向上处理
					cur = grandfather;
					parent = cur->_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(iterator(newNode), true);

	}
	//情况二和情况三旋转+变色以后,这颗字数不违反红黑树规则,相比插入前,黑色节点的数量是不变的,不会影响上层,处理就结束了
	iterator Find(const K& key)
	{
		Node* cur = _root;
		KeyOfT kot;
		while (cur)
		{
			if (kot(cur->_data) < key)
			{
				cur = cur->_right;
			}
			else if(kot(cur->_data) > key)
			{
				cur = cur->_left;
			}
			else
			{
				return iterator(cur);
			}
		}
		return End();
	}


private:
	//左单旋
	void RotateL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;

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

		parent->_left = subLR;
		if (subLR)
			subLR->_parent = parent;
		Node* ppNode = parent->_parent;
		subL->_right = parent;
		parent->_parent = subL;
		if (_root == parent)
		{
			_root = subL;
			_root->_parent = nullptr;
		}
		else
		{
			if (ppNode->_left == parent)
			{
				ppNode->_left = subL;
			}
			else
			{
				ppNode->_right = subL;
			}
			subL->_parent = ppNode;
		}
	}

private:
	Node* _root = nullptr;

};

1.3 set的模拟实现

set的底层为红黑树,因此只需在set内部封装一棵红黑树,即可将该容器实现出来。

namespace hulu
{
	template<class K>
	class set
	{
		struct SetKeyOfT
		{
			const K& operator()(const K& k)
			{
				return k;
			}

		};
	public:
		typedef typename RBTree<K, K, SetKeyOfT>::const_iterator iterator;
		typedef typename RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;
		pair<iterator,bool> insert(const K& key)
		{
			pair<typename RBTree<K, K, SetKeyOfT>::iterator, bool> ret = _t.insert(key);
			return pair<iterator, bool>(iterator(ret.first._node),ret.second);
		}

		iterator begin()const
		{
			return _t.Begin();
		}
		iterator end()const
		{
			return _t.End();
		}
		iterator find(const K& key)
		{
			return _t.Find(key);
		}
	private:
		RBTree<K, K, SetKeyOfT> _t;

	};
}

1.4 map的模拟实现

map的底层结构就是红黑树,因此在map中直接封装一棵红黑树,然后将其接口包装下即可。

namespace hulu
{
	template<class K,class V>
	class map
	{
		struct MapKeyOfT
		{
			const K& operator()(const pair<K,V>& kv)
			{
				return kv.first;
			}

		};
	public:
		typedef typename RBTree<K, pair<K, V>, MapKeyOfT>::iterator iterator;
		typedef typename RBTree<K, pair<K, V>, MapKeyOfT>::const_iterator const_iterator;

		iterator begin()
		{
			return _t.Begin();
		}
		iterator end()
		{
			return _t.End();
		}
		pair<iterator, bool> insert(const pair<K, V>& kv)
		{
			return _t.insert(kv);
		}
		iterator find(const K& key)
		{
			return _t.Find(key);
		}
		V& operator[](const K& key)
		{
			pair<iterator, bool> ret = insert(make_pair(key,V()));
			return ret.first->second;
		}
	private:
		RBTree<K, pair<K, V>, MapKeyOfT> _t;

	};
}

附录

迭代器的实现

template<class T,class Ref,class Ptr>
struct __RBTreeIterator
{ 
	typedef RBTreeNode<T> Node;
	typedef __RBTreeIterator<T, Ref, Ptr> Self;
	__RBTreeIterator(Node* node)
		:_node(node)
	{}
	Ref operator*()
	{
		return _node->_data;
	}
	Ptr operator->()
	{
		return &_node->_data;
	}
	Self& operator++()
	{
		if (_node->_right == nullptr)
		{
			//找该节点是祖先的左节点的祖先节点
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent&& parent->_right==cur)
			{
				cur = cur->_parent;
				parent = parent->_parent;
			}
			_node = parent;
		}
		else
		{
			//右子树的最左节点
			Node* subLeft = _node->_right;
			while (subLeft->_left)
			{
				subLeft = subLeft->_left;
			}
			_node = subLeft;
		}
		return *this;
	}
	Self operator++(int)
	{
		Self tmp(*this);
		++(*this);
		return *this;
	}
	Self& operator--()
	{
		if (_node->_left == nullptr)
		{
			//找该节点是祖先的右节点的祖先节点
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent&&parent->_left == cur)
			{
				cur = cur->_parent;
				parent = parent->_parent;
			}
			_node = parent;
		}
		else
		{
			//找左子树的最右节点
			Node* subRight = _node->_left;
			while (subRight->_right)
			{
				subRight = subRight->_right;
			}
			_node = subRight;
		}
	}
	Self operator--(int)
	{
		Self tmp(*this);
		--(*this);
		return *this;
	}
	bool operator!=(const Self& s)const
	{
		return _node != s._node;
	}
	bool operator==(const Self& s)const
	{
		return _node == s._node;
	}
	Node* _node;
};

(本章完!)

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

拾至灬名瑰

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

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

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

打赏作者

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

抵扣说明:

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

余额充值