封装map和set

我们已经知道,map和set的底层是红黑树。而在底层红黑树节点中,我们并不知道上层传过来的是map的pair类型还是set的key。因此我们对红黑树的节点不能直接单纯的写死成两个模板参数,而是要运用泛型的思想,根据上层传的Value来确定是key搜索类型还是key/value搜索类型。

enum Color
{
	RED,
	BLACK
};

template<class T>
struct RBTreeNode	
{
	T _data;
	RBTreeNode<T>* _left;
	RBTreeNode<T>* _right;
	RBTreeNode<T>* _parent;
	Color _col;

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

模拟实现map和set
实现出复用红黑树的框架,并支持insert

1、因为RBTree实现了泛型不知道T参数导致是K,还是pair<K,V>,那么insert内部进行插入逻辑比较时,就没办法进行比较,因为pair的默认支持的是key和value一起参与比较,我们需要时的任何时候只比较key,所以我们在map和set层分别实现一个MapKeyOfT和SetKeyOfT的仿函数传给RBTree的KeyOfT,然后RBTree中通过KeyOfT仿函数取出T类型对象中的key,再进行比较。

template<class K>
class set
{
	struct SetKeyOfT
	{
		const K& operator()(const K& key)
		{
			return key;
		}
	};
private:
	RBTree<K, const K, SetKeyOfT> _t;
}; 


template<class K, class V>
class map
{
	struct MapKeyOfT
	{
		const K& operator()(const pair<K, V>& kv)
		{
			return kv.first;
		}
	};
private:
	RBTree<K, pair<const K,V> , MapKeyOfT> _t;
};



template<class K, class T, class KeyOfT>
class RBTree
{
	typedef RBTreeNode<T> Node;
    RBTree()
	    :_root(nullptr)
	    ,_size(0)
    {}

	Node* _root;
};

2、对于map和set的迭代器

①iterator实现的大框架跟list的iterator思路是一致的,用一个类型封装结点的指针,再通过重载运算符实现,迭代器像指针一样访问的行为。

②operator++和operator--是迭代器实现中的难点,我们知道红黑树的遍历是按照中序遍历进行的。

③对于operator++,分为两种情况:如果该节点的右子树不为空,则去找右子树的最左节点。如果右子树为空,说明当前子树已经遍历完了,那么就要回溯到祖先去找下一个节点,怎么回溯呢?如果该节点是父亲节点的右孩子,这个节点所在子树已经遍历完了,而该子树有充当着父亲节点的右子树,说明父亲节点所在字数也遍历完成,那就需要继续向上回溯,直到当前节点是父亲的左孩子,说明父亲节点的左子树遍历完成,按照中序遍历“左->根->右”的顺序,下一步就要遍历父亲节点了,因此回溯结束,下一个节点就是该父亲节点。

④operator--的实现思路和operator++在逻辑上刚好相反,也是分为两种情况:第一、如果该节点的左子树不为空,说明遍历到该节点是由于该节点的左子树遍历完成后再接着遍历该节点的,因此要找上一个节点的话,需要找到左子树遍历完成的最后一个节点,也就是左子树的最右节点。如果左子树为空,说明遍历到该节点是由于某个祖先节点遍历遍历完后接着遍历右子树时将当前节点作为了右子树的最左节点最先遍历,因此往上回溯时需要找到孩子是父亲右的那个父节点。

⑤end()怎么表示:我们习惯上用nullptr作为end()

⑥set的iterator不支持修改,我们把set的第二个模板参数改成const K即可

RBTree<K,const K, SetKeyOfT> _t

⑦map的iterator也不支持修改key但是可以修改value,我们把map的第二个模板参数pair的第一个参数改成const K即可

RBTree<K, pair<const K, V>, MapKeyOfT> _t; 

⑧一个细节是,对于前置++和前置--,我们返回对象的引用,但是对于后置++和后置--,我们返回对象本身,这是因为前置直接修改对象并返回修改后的对象,使用引用可以减少拷贝,而后置返回的是一个临时对象,不允许引用返回。

RBTreeIterator的实现

//迭代器
template<class T, class Ref, class Ptr>
struct RBTreeIterator
{
	typedef RBTreeNode<T> Node;
	typedef RBTreeIterator<T, Ref, Ptr> Self;

	Node* _node;
	Node* _root;

	RBTreeIterator(Node* node, Node* root)
		:_node(node)
		,_root(root)
	{}

	Self& operator++()
	{
		if (_root == nullptr)
			return *this;
		if (_node->_right)
		{
			Node* cur = _node->_right;
			while (cur->_left)
			{
				cur = cur->_left;
			}
			_node = cur;
		}
		else 
		{
			Node* parent = _node->_parent;
			while (parent && _node == parent->_right) 
			{
				_node = parent;
				parent = parent->_parent;
			}
			_node = parent;
		}
		return *this;
	}

	Self operator++(int) 
	{
		Self tmp = *this;
		++(*this);
		return tmp;
	}

	Self& operator--()
	{
		if (_node == nullptr)
		{
			Node* cur = _root;
			while (cur->_right)
				cur = cur->_right;
			_node = cur;
			return *this;
		}
			
		if (_node->_left)
		{
			Node* cur = _node->_left;
			while (cur->_right)
				cur = cur->_right;
			_node = cur;
			return *this;
		}
		else
		{
			Node* parent = _node->_parent;
			while (parent && _node == parent->_left)
			{
				_node = parent;
				parent = parent->_parent;
			}
			_node = parent;
			return *this;
		}
	}

	Self operator--(int) 
	{
		Self tmp = *this;
		--(*this);
		return tmp;
	}

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

在红黑树中,我们通过typedef来套用这一层迭代器,并且分为普通迭代器和const迭代器,然后定义红黑树的begin()和end(),并且将Insert、Find的返回值都使用迭代器。注意,库里insert的返回值也是一个pair类型

红黑树的改造和迭代器套用:

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*> ConstIterator;
	RBTree()
		:_root(nullptr)
		,_size(0)
	{}

	Iterator Begin() 
	{
		Node* cur = _root;
		while (cur->_left)
			cur = cur->_left;
		return Iterator(cur, _root);
	}

	Iterator End() 
	{
		return Iterator(nullptr, _root);
	}

	ConstIterator Begin() const
	{
		Node* cur = _root;
		while (cur->_left)
			cur = cur->_left;
		return ConstIterator(cur, _root);
	}

	ConstIterator End() const
	{
		return ConstIterator(nullptr, _root);
	}

	pair<Iterator,bool> Insert(const T& data)
	{
		KeyOfT kot;
		if (_root == nullptr)
		{
			_root = new Node(data);
			_root->_col = BLACK;//根节点必须是黑色
			_size++;
			return make_pair(Iterator(_root,_root),true);
		}

		//插入节点逻辑
		Node* parent = nullptr;
		Node* cur = _root;

		while (cur)
		{
			if (kot(cur->_data) == kot(data))
				return make_pair(Iterator(cur,_root),false);
			else if (kot(cur->_data) < kot(data))
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				parent = cur;
				cur = cur->_left;
			}
		}

		Node* node = new Node(data);
		if (kot(data) < kot(parent->_data))
			parent->_left = node;
		else
			parent->_right = node;
		node->_parent = parent;
		_size++;

		//更新颜色
		cur = node;
		while (parent && parent->_col == RED)
		{
			Node* pparent = parent->_parent;
			Node* uncle;
			if (parent == pparent->_left)//parent为左
			{
				uncle = pparent->_right;
				//叔叔存在且为红
				if (uncle && uncle->_col == RED)
				{
					parent->_col = uncle->_col = BLACK;
					pparent->_col = RED;

					parent = pparent->_parent;
					cur = pparent;
				}
				else if (!uncle || uncle->_col == BLACK) //叔叔不存在/存在且为黑
				{
					if (cur == parent->_right)//左右->左右双旋
					{
						RotateL(parent);
						swap(parent, cur);//将左旋和左右双旋统一
					}
					//左左->右单旋
					RotateR(pparent);
					parent->_col = BLACK;
					pparent->_col = RED;
					break;
				}
			}
			else//parent为右
			{
				//叔叔存在且为红
				uncle = pparent->_left;
				if (uncle && uncle->_col == RED)
				{
					parent->_col = uncle->_col = BLACK;
					pparent->_col = RED;

					parent = pparent->_parent;
					cur = pparent;
				}
				else if (!uncle || uncle->_col == BLACK)
				{
					if (cur == parent->_left)//右左->右左双旋双旋
					{
						RotateR(parent);
						swap(parent, cur);
					}
					//右右->左单旋
					RotateL(pparent);
					parent->_col = BLACK;
					pparent->_col = RED;
					break;
				}
			}
		}
		_root->_col = BLACK;
		return make_pair(Iterator(node,_root),true);
	}

	Iterator 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 Iterator(cur,_root);
			}
		}
		return Iterator(nullptr,_root);
	}

	bool IsBalance()
	{
		if (_root == nullptr)
			return true;

		if (_root->_col == RED)
			return false;

		int refNum = 0;
		Node* cur = _root;
		while (cur)
		{
			if (cur->_col == BLACK)
				refNum++;

			cur = cur->_left;
		}

		return Check(_root, 0, refNum);
	}

	// 中序遍历
	void InOrder() 
	{
		_InOrder(_root);
		cout << endl;
	}
	size_t _size;
	bool Empty() const { return _size == 0; }
private:
	void RotateR(Node* parent)
	{
		//连接子
		Node* pparent = parent->_parent;
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
		KeyOfT kot;

		parent->_left = subLR;
		subL->_right = parent;	
		if (pparent == nullptr)
		{
			_root = subL;
			subL->_parent = nullptr;
		}
		else
		{
			if (kot(parent->_data) < kot(pparent->_data))
				pparent->_left = subL;
			else
				pparent->_right = subL;
			subL->_parent = pparent;
		}

		//链接父
		if (subLR)
			subLR->_parent = parent;
		parent->_parent = subL;
	}

	void RotateL(Node* parent)
	{
		//连接子
		Node* pparent = parent->_parent;
		Node* subR = parent->_right;
		Node* subRL = subR->_left;
		KeyOfT kot;

		parent->_right = subRL;
		subR->_left = parent;
		if (pparent == nullptr)
		{
			_root = subR;
			subR->_parent = nullptr;
		}
		else
		{
			if (kot(parent->_data) < kot(pparent->_data))
				pparent->_left = subR;
			else
				pparent->_right = subR;
			subR->_parent = pparent;
		}

		//链接父
		if (subRL)
			subRL->_parent = parent;
		parent->_parent = subR;
	}

	/*void RotateLR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;

		RotateL(subL);
		RotateR(parent);
	}

	void RotateRL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;

		RotateR(subR);
		RotateL(parent);
	}*/

	bool Check(Node* root, int blackNum, const int refNum)
	{
		if (root == nullptr)
		{
			if (blackNum != refNum)
			{
				cout << "存在黑色节点数量不相等的路径" << endl;
				return false;
			}
			return true;
		}

		if (root->_col == RED && root->_parent && root->_parent->_col == RED)//避免空指针访问
		{
			cout << "存在连续的红色节点" << endl;
			return false;
		}

		if (root->_col == BLACK)
			blackNum++;

		return Check(root->_left, blackNum, refNum) && Check(root->_right, blackNum, refNum);
	}

	// 中序遍历辅助函数
	void _InOrder(Node* root) 
	{
		if (root == nullptr) 
			return;
		_InOrder(root->_left);
		cout << root->_kv.first << "(" << (root->_col == RED ? "R" : "B") << ") ";
		_InOrder(root->_right);
	}

	Node* _root;
};

而在set和map层套用迭代器,同样使用typedef即可,注意通过::取类里面的东西时,如果取出来的是一个类型,需要声明typename,因为编译器并不能确认你从类里面取的是变量还是类型

template<class K>
class set
{
	struct SetKeyOfT
	{
		const K& operator()(const K& key)
		{
			return key;
		}
	};
public:
	typedef typename RBTree<K, const K, SetKeyOfT>::Iterator iterator;
	typedef typename RBTree<K, const K, SetKeyOfT>::ConstIterator const_iterator;
	iterator beign()
	{
		return _t.Begin();
	}
	iterator end()
	{
		return _t.End();
	}
	const_iterator begin() const
	{
		return _t.Begin();
	}
	const_iterator end() const
	{
		return _t.End();
	}
	bool empty() const
	{
		return _t.Empty();
	}
	size_t size() const
	{
		return _t._size;
	}
	pair<iterator ,bool> insert(const K& key)
	{
		return _t.Insert(key);
	}
	iterator find(const K& key) const
	{
		return _t.Find(key);
	}
private:
	RBTree<K, const K, SetKeyOfT> _t;
}; 

对于map,我们还需要重载map的[],map的[]有两种情况,如果key不存在,就插入,并返回插入后value的引用,如果key存在,则插入失败,充当查找功能,返回value的引用。

template<class K, class V>
class map
{
	struct MapKeyOfT
	{
		const K& operator()(const pair<K, V>& kv)
		{
			return kv.first;
		}
	};
public:
	//注意是pair里的K加const而不是pair加const
	typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::Iterator iterator;
	typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::ConstIterator const_iterator;
	iterator begin()
	{
		return _t.Begin();
	}
	iterator end()
	{
		return _t.End();
	}
	const_iterator begin() const
	{
		return _t.Begin();
	}
	const_iterator end() const
	{
		return _t.End();
	}
	bool empty() const
	{
		return _t.Empty();
	}
	size_t size() const
	{
		return _t._size;
	}
	pair<iterator, bool> insert(const pair<K,V>& kv)
	{
		return _t.Insert(kv);
	}
	iterator find(const K& key) const
	{
		return _t.Find(key);
	}
	V& operator[](const K& key)
	{
		pair<iterator, bool> ret = _t.Insert(make_pair(key,V()));
		//ret.first是一个迭代器,使用->解引用得到_data,而map传给T为pair<K,V>类型,隐藏了第二层
		//pair取second的->
		return ret.first->second;
	}
private:
	RBTree<K, pair<const K,V> , MapKeyOfT> _t;
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值