红黑树封装map和set

1.map和set

map与set的底层是红黑树,直接在map与set中封装一棵红黑树,然后包装其接口。

2.改造红黑树

如果我们要将红黑树拿去封装map和set的话,首先需要增加迭代器,便于map与set的遍历。

template <class T,class Ref, class Ptr>
	struct __RBTreeIterator
	{
		typedef RBTreeNode<T> Node;
		Node* _node;

		__RBTreeIterator(Node* node)
			:_node(node)
		{}

		__RBTreeIterator(const __RBTreeIterator<T,T&,T*>& it)
			:_node(it._node)
		{}

		typedef __RBTreeIterator<T,Ref,Ptr> Self;

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

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

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

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

				_node = parent;
			}

			return *this;
		}

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

				_node = parent;
			}

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

2.1 operator++与--

operator++分为有右子树和没有右子树两种情况。顺序是中序遍历,左根右。

右不为空,下一个就是右子树的最左节点。

右为空,沿着到根的路径,找孩子是父亲左的那个祖先。

 operator--则相反,分为左子树为空和左子树不为空两种情况。

左子树不为空,去找左子树的最右节点。

左子树为空,沿着到根的路径,找孩子是父亲右的那个祖先。

与中序遍历相反,右根左。

2.2 begin与end

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* cur = _root;
			while (cur && cur->_left)
			{
				cur = cur->_left;
			}
			return Iterator(cur);
		}

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

begin直接是左子树的最左节点,end直接给空指针。

3.map

#pragma once
#include "RBTree.h"

namespace L
{
	template <class K, class V>
	class map
	{
		struct MapKeyofT
		{
			const K& operator()(const pair<const K, V>& kv)
			{
				return kv.first;
			}
		};
	public:
		typedef typename RBTree<K, pair<const K, V>, 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);
		}

		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>, MapKeyofT> _t;
	};

直接套用红黑树的接口。map的插入函数的返回值需要设计成pair<iterator,bool>的形式,以便于operator[]能实现插入+修改Val的功能。

4.set

#pragma once
#include "RBTree.h"

namespace L
{
	template <class K>
	class set
	{
		struct SetKeyofT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};
	public:
		typedef typename RBTree<K, K, SetKeyofT>::const_Iterator Iterator;
		typedef typename RBTree<K, K, SetKeyofT>::const_Iterator 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();
		}

		pair<Iterator, bool> Insert(const K& key)
		{
			return _t.Insert(key);
		}
	private:
		RBTree<K, K, SetKeyofT> _t;
	};

5.迭代器隐式类型转换问题

由于set中不允许修改key,所以set的迭代器都是设计成const迭代器。

typedef typename RBTree<K, K, SetKeyofT>::const_Iterator Iterator;
typedef typename RBTree<K, K, SetKeyofT>::const_Iterator const_Iterator;

而set在调用红黑树的begin时,返回的是一个普通迭代器,而普通迭代器无法转换成const迭代器。那把红黑树里的迭代器都设计成const迭代器行不行呢?答案是不行,因为map里需要普通迭代器来修改val。

typedef typename RBTree<K, pair<const K, V>, MapKeyofT>::Iterator Iterator;

为此我们需要在红黑树迭代器里设计一个特殊的构造函数。

__RBTreeIterator(const __RBTreeIterator<T,T&,T*>& it)
			:_node(it._node)
		{}

当传进来的是普通迭代器时,这个构造函数就是拷贝构造。

当传进来的是const迭代器时,这个构造函数就是一个支持用普通迭代器来构造const迭代器的构造函数。这个构造函数是一个单参数的隐式类型转换构造函数,把普通迭代器转换成了模板实例化的const迭代器对象本身。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值