map_set的简单模拟实现

树结点的定义

map和set的底层都是红黑树,由于set是Key型,而map是key-value型,这就需要我们的红黑树是一种泛型,实现set时树节点内存放的值时Key,当实现map时树结点所储存的值就需要是存放Key-value的值的pair类型.

因此我们应该这样定义红黑树的结点、

template <class V>
class RBTreeNode
{
public:
	RBTreeNode* _left;
	RBTreeNode* _parent;
	RBTreeNode* _right;

	Color _color;
	V _data;  //根据传入类型来确定存储值


	RBTreeNode(const V& data)
		:_left(nullptr)
		,_right(nullptr)
		,_parent(nullptr)
		,_data(data)
		,_color(RED)
	{

	}

};

红黑树的定义

包含了构造红黑树的过程以及旋转操作:不懂可以看看我的红黑树和AVL树的笔记

template<class K,class V,class KeyOfValue>
class RBTree
{
	typedef RBTreeNode<V> Node;
	KeyOfValue kov;

public:
	typedef __Tree_iterator<V,V*,V&> iterator;

	typedef __Tree_iterator<V,const V*,const V&> const_iterator; //const类型迭代器

	iterator begin()
	{
		Node* cur = _root;
		while( cur && cur->_left)
		{
			cur = cur->_left;
		}

		return iterator(cur);
	}

	iterator end()
	{
		return iterator(nullptr);
	}

	const_iterator begin() const
	{
		Node* cur = _root;
		while (cur && cur->_left)
		{
			cur = cur->_left;
		}

		return const_iterator(cur);
	}

	const_iterator end() const
	{
		return const_iterator (nullptr);
	}



	Node* Find(const K& key)
	{
		Node* cur = _root;

		KeyOfValue kot;
		while (cur)
		{
			if (kot(cur->_data) < key)
			{
				cur = cur->_right;
			}
			else if (kot(cur->_data) > key)
			{
				cur = cur->_left;
			}
			else
			{
				return cur;
			}
		}

		return nullptr;
	}


	pair<iterator,bool> Insert(const V& data)
	{
		if (_root == nullptr)
		{
			_root = new Node(data);
			_root->_color = BLACK;

			return make_pair(iterator(_root),true);
		}

		Node* cur = _root;
		Node* parent = nullptr;
		while (cur)
		{
			if (kov(cur->_data) < kov(data))
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (kov(cur->_data) > kov(data))
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				return make_pair(iterator(cur), false);
			}
		}
		//到达插入位置
		cur = new Node(data);
		cur->_color = RED;

		Node* newnode = cur;
		if ( kov(parent->_data) < kov(cur->_data))
		{
			parent->_right = cur;
		}
		else
		{
			parent->_left = cur;
		}

		cur->_parent = parent;

		//开始构建红黑树

		while (parent && parent->_color == RED)//父亲存在并且颜色为红色
		{
			Node* grandfather = parent->_parent; //找到祖父结点
		
			if (parent == grandfather->_left)   //如果父亲是祖父的左孩子
			{ 
				Node* uncle = grandfather->_right; //叔叔就是祖父的有孩子

				if (uncle && uncle->_color == RED) //如果叔叔存在并且叔叔的颜色为红色
				{
					parent->_color = BLACK;			//将父亲和叔叔改为黑色 将祖父改为红色
					uncle->_color = BLACK;

					grandfather->_color = RED;

					cur = grandfather;				//继续向上更新
					parent = cur->_parent;
				}
				else   ////如果叔叔不存在或者叔叔的颜色为黑色 就需要进行旋转
				{
					if (cur == parent->_left)   //因为 父亲是祖父的左孩子 如果cur是父亲的的左孩子 (左左) 只需要进行右单旋
					{
						RotateR(grandfather);

						//旋转后跟新结点颜色
						grandfather->_color = RED;

						parent->_color = BLACK;


					}
					else   //父亲是祖父的左孩子 如果cur是父亲的的右孩子 (左右) 先进行左旋 在进行右旋
					{
						RotateL(parent);
						RotateR(grandfather);

						//旋转后跟新结点颜色
						grandfather->_color = RED;
						cur->_color = BLACK;
					}
				
				

					break;
				}
			}
			else//parent == grandfather->_right   如果父亲是祖父的孩子
			{
				Node* uncle = grandfather->_left;

				if (uncle && uncle->_color == RED)  //叔叔存在并且为红色
				{
					parent->_color = BLACK;    //将父亲和叔叔改为黑色 将祖父改为红色
					uncle->_color = BLACK;

					grandfather->_color = RED;

					cur = grandfather;          //继续向上更新
					parent = cur->_parent;
				}
				else                                  ///如果叔叔不存在或者叔叔的颜色为黑色 就需要进行旋转
				{
					if (cur == parent->_right) //因为 父亲是祖父的右孩子 如果cur是父亲的的右孩子 (右右) 只需要进行左单旋
					{
						RotateL(grandfather);

						grandfather->_color = RED;
						parent->_color = BLACK;
					
					}
					else// 父亲是祖父的右孩子 如果cur是父亲的的左孩子 (右左) 先进行右单旋 再 进行左单旋
					{
						RotateR(parent);
						RotateL(grandfather);

						grandfather->_color = RED;
						cur->_color = BLACK;

					}

					break;
				}

			}
		}

		_root->_color = BLACK;
		return make_pair(iterator(newnode), true);

	
	}


	
	

private:

	void RotateR(Node* parent)
	{
		Node* cur = parent->_left;
		Node* curright = cur->_right;

		parent->_left = curright;

		if (curright)
		{
			curright->_parent = parent;
		}

		cur->_right = parent;

		Node* ppNode = parent->_parent;

		parent->_parent = cur;


		if (ppNode == nullptr)
		{
			_root = cur;
			cur->_parent = nullptr;
		}
		else
		{
			if (ppNode->_left == parent)
			{
				ppNode->_left = cur;
			}
			else
			{
				ppNode->_right = cur;
			}

			cur->_parent = ppNode;

		}
	}

	void RotateL(Node* parent)
	{
		Node* cur = parent->_right;
		Node* curleft = cur->_left;

		parent->_right = curleft;

		if (curleft)
		{
			curleft->_parent = parent;
		}

		cur->_left = parent;

		Node* ppNode = parent->_parent;

		parent->_parent = cur;


		if (ppNode == nullptr)
		{
			_root = cur;
			cur->_parent = nullptr;
		}
		else
		{
			if (ppNode->_left == parent)
			{
				ppNode->_left = cur;
			}
			else
			{
				ppNode->_right = cur;
			}

			cur->_parent = ppNode;

		}
	}



	Node* _root = nullptr;

};

在图中我们看见在类模板中除了K和V我们发现还有一个KeyOfValue的类型,这是干什么的呢?

其实他是一个仿函数,为了我们方便从结点中的V类型提取我们所需要的Key值,当此红黑树用来定义set时,树结点中存放的V的类型就是K,用KeyOfValue来获取key值,当用来实现map时,用KeyOfValue来获取pair类型中的Key值。他的具体定义会在map和set的定义中实现。

map和set的迭代器

++操作

在实现迭代器的过程中最困难的部分就是迭代器的++和--操作

++操作该怎么做呢(它的核心本质就是树的中序  左子树  根   右子树)

我们分为两种情况:第一 当目前结点的右孩子不为空时,我们只需要去寻找当前结点右子树的最小值,第二种情况 当目前结点的右孩子为空时,我们需要找到下一个结点应该是 ---当前结点是其父亲的左指针 那么下一个结点就是当前结点的父亲,如果当前结点是其父亲的右指针,那么我们就继续向上更新 ,寻找下一个结点

template<class V>
struct __Tree_iterator
{
	typedef RBTreeNode<V> Node;
	typedef __Tree_iterator<V> Self;
	Node* _node;
	__Tree_iterator(Node* node)
		:_node(node)
	{ 
	}

	bool operator!=(const Self& v)
	{
		return _node != v._node;
	}
	V& operator*()
	{
		return _node->_data;
	}

	V* operator->()
	{
		return &(_node->_data);
	}

	Self& operator++()
	{
		
			if (_node->_right)
			{
				Node* it = _node->_right;
				while (it->_left)
				{
					it = it->_left;
				}

				_node = it;
			}
			else
			{
				Node* cur = _node;
				Node* parent = _node->_parent;
				while (parent  && cur == parent->_right)
				{
					
						cur = cur->_parent;
						parent = parent->_parent;

					
				}
				_node = parent;
				
			}

		return *this;

	}



};

--操作

--的操作方法和++的方法是相反的

同样我们分为两种情况:第一种:当前结点的左子树如果不为空,那么下一个访问结点就是当前结点左子树的最大值,第二种情况:当前结点的左子树为空。我们就需要更新cur(更新当前节点)和parent,直到cur是其父亲结点的右子树,那么下一个访问结点就是cur的父亲结点

Self& operator--()
{
	if (_node->_left)
	{
		Node* subright = _node->_left;

		while (subright->_right)
		{
			subright->_right;
		}
		_node = subright;
	}
	else
	{
		Node* cur = _node;
		Node* parent = _node->_parent;

		while (parent && cur == parent->_left)
		{

			cur = parent;
			parent = parent->_parent;
		}

		_node = parent;

	}
	return *this;

}

迭代器的定义及其他操作

template<class V,class Ptr,class Ref>
struct __Tree_iterator
{
	typedef RBTreeNode<V> Node;

	typedef __Tree_iterator<V ,Ptr, Ref> Self;

	typedef  __Tree_iterator<V, V*, V&> iterator; //此处的typedef是为了 
                                                  //用普通迭代器构造const迭代器

	Node* _node;
	__Tree_iterator(Node* node)
		:_node(node)
	{ 
	}
	__Tree_iterator( const iterator& it) //如果是普通迭代器那么这是拷贝构造
		:_node(it._node)                  // 如果是const迭代器那么这是 一种构造函数 用于将
	{                                     //普通迭代器构造成const迭代器
	}


	bool operator!=(const Self& v)
	{
		return _node != v._node;
	}

	Ref operator*()
	{
		return _node->_data;
	}

	Ptr operator->()
	{
		return &(_node->_data);
	}



};

set的模拟实现

set的封装:


	template<class K>
class set
{

	struct SetOfValue
	{
		K operator()(const K& key)
		{
			return key ;
		}
	};

public:

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

	iterator begin() const
	{
		return t.begin();
	}

	iterator end() const
	{
		return t.end();
	}

	pair<iterator,bool> Insert(const K& key)
	{
		pair< typename RBTree<K, K, SetOfValue>::iterator , bool> ret = t.Insert(key);

		return pair < iterator, bool >(ret.first, ret.second);
	}

private:

	RBTree<K, K, SetOfValue> t;
};

因为set是不可修改的容器所以我们的普通迭代器和const迭代器都是const迭代器,inser的返回了类型是pair类型,由于在set中的迭代器是const迭代器,而在调用insert函数时,t 是普通对象,所以返回的是普通迭代器的对象,因此才需要了在定义迭代器是需要将普通迭代器构造成const迭代器的构造函数,所以在insert函数中,我们先接受普通迭代器的pair类型,再用普通迭代器来构造const迭代器。

map的模拟实现

map的封装:

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

	};

public:

	typedef typename RBTree<K, pair<const K, V>, MapOfValue>::iterator iterator;
	typedef typename RBTree<K, pair<const K, V>, MapOfValue>::const_iterator const_iterator;

	//typedef typename RBTree<K, pair<K, V>, MapOfValue>::iterator iterator;

	pair<iterator,bool> Insert(const pair<const K, V>& kv)
	{
		return	t.Insert(kv);
		
	}

	iterator begin() 
	{
		return t.begin();
	}

	iterator end() 
	{
		return t.end();
	}

	const_iterator begin() const
	{
		return t.begin();
	}

	const_iterator end() const
	{
		return t.end();
	}

	V& operator[](const K& key)
	{
		pair<iterator, bool> ret = t.Insert(make_pair(key,V()));
		return ret.first->second;

	}

private:

	RBTree<K, pair<const K,V>,MapOfValue> t;
};

在map中应为Key值是不可以修改的,而Value时可以修改的,所以我们在定义时就将pair类中的Key定义为const。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

晚风吹长发

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

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

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

打赏作者

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

抵扣说明:

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

余额充值