Map和Set的封装(RBTree实现,包含迭代器)

Map和Set的封装(RBTree实现,包含迭代器)



用RBTree封装Map和Set主要需要解决以下几个问题

  1. Set存储的是key,Map存储的是key/value,如何用RBTree兼容两者
  2. Map和Set迭代器的初步实现
  3. 如何解决Set中key不能被修改,Map中key不能被修改,value能被修改的问题
  4. Insert插入返回值问题以及Map[]的重载实现

一、问题1

Set存储的是key,Map存储的是key/value,如何用RBTree兼容两者实现封装呢?
我们可以查看库中的源码,如下图:
在这里插入图片描述
我们不难看出在库中红黑树的实现有五个个模板参数,我们重点看前三个
分别是 Key ,Value , KeyOfValue
而其中第二个Value就是决定node中存什么结构的

明白这一点就引出了下一个问题
如果是key结构,红黑树在插入的时候可以直接比较,但如果是key/value结构,本质上是一个键值对pair<first,second>,键值对能直接比较吗,我们可以查阅了文档,
如图:
在这里插入图片描述
此处说明对于pair的比较,first和second只要有一个小,pair就小,但这和我们想要的规则不同,我们要做的是搜索二叉树的插入,比较的仅仅只有key值,并且key值相同时无法插入。

所以接下来需要解决比较这个问题,而如何解决的答案就在第三个模板参数 KeyOfValue 上,KeyOfValue是一个内部类,是map和set内部实现的一个类,该类中实现了一个仿函数operator(),而该仿函数返回的值就是需要比较的key,这么讲可能有点抽象,上代码图帮助理解
在这里插入图片描述
这是一个泛型的思想,无论是map还是set,都能一套实现,set中就是走个过场直接返回key,而map中返回pair中的first

二、问题2

map和set的迭代器本质上是复用红黑树中的迭代器,所以我们先实现红黑树的迭代器
首先我们需要明确的是,红黑树是一个双向迭代器,支持+ +,- -操作,并且因为红黑树是一颗搜索二叉树,既然设计迭代器,迭代器就需要有价值,所以迭代器应该走的是红黑树的中序遍历
在这里插入图片描述
迭代器的begin指向的应该是树的最左节点,end指向的是空

主要实现迭代器 =,++,- -,*,->,==,!= 的功能
此处应该没什么难点,树的迭代器的本质就是封装了树的节点
值得一提的是++与- -运算符的实现,由于我们走的是中序遍历,如何找到下一个节点或者如何找到上一个节点,需要仔细想想,代码处提供了思路,这里不多赘述

template <class T>
struct _treeiterator
{
    typedef TreeNode<T> Node;

    typedef _treeiterator<T> Self;

    Node* _node;

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

	_treeiterator(const iterator& x)
		:_node(x._node)
	{}

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

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

    //有右孩子,找右孩子的最左节点
    //没右孩子,找孩子是父亲的左节点的祖先
    Self& operator++()
    {
        if (_node->_right)
        {
            _node = _node->_right;

            while (_node->_left)
            {
                _node = _node->_left;
            }

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

            _node = parent;

        }

        return *this;
    }

    //有左孩子,找左孩子的最右节点
    //没左孩子,找孩子是父亲的右节点的祖先
    Self& operator--()
    {
        if (_node->_left)
        {
            _node = _node->_left;

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

            while (parent && parent->_left == _node)
            {
                _node = parent;
                parent = _node->_parent;
            }

            _node = parent;
        }

        return *this;
    }

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

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

};

三、问题3

在初步实现了迭代器以后,在map和set中复用上,就能够遍历树了
但还存在一定的问题,*it时无论是set的key还是map的first都能被修改,如果树中的key能够被允许修改,那么红黑树将毫无意义,因为红黑树是一颗搜索二叉树,正是因为它的结构,使得有排序和查找的价值,一但结构被破坏,就丧失了其价值
所以我们还需要进一步解决key不能被修改的问题

我们参考库中解决Set中key不能被修改,Map中key不能被修改,value能被修改的问题
在这里插入图片描述
我们可以看出库中set的iterator和const_iterator都是红黑树的const_iterator复用而来
map中的iterator是红黑树的iterator复用而来,const_iterator是红黑树的const_iterator复用而来,而map解决key不能被修改,value能被修改的原理也很简单,就是在实例化的时候,声明第二个模板参数——在map中也就是pair,pair的first是const类型

所以,我们还需要实现红黑树的const_iterator,map中的iterator和const_iterator都用其复用

更值得注意的是const_iterator的实现不仅仅是在iterator前面加一个const,因为iterator是一个封装的类,iterator和const_iterator是两个不同的类,所以要实现红黑树的const_iterator的话就需要再用到模板,是什么迭代器取决于实例化的时候是什么类型的参数

template <class T, class Ref, class Ptr>
struct _treeiterator
{
    typedef TreeNode<T> Node;

    typedef _treeiterator<T, T&, T*> iterator;
    typedef _treeiterator<T, Ref, Ptr> Self;

    Node* _node;

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

    _treeiterator(const iterator& x)
        :_node(x._node)
    {}

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

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

    //有右孩子,找右孩子的最左节点
    //没右孩子,找孩子是父亲的左节点的祖先
    Self& operator++()
    {
        if (_node->_right)
        {
            _node = _node->_right;

            while (_node->_left)
            {
                _node = _node->_left;
            }

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

            _node = parent;

        }

        return *this;
    }

    //有左孩子,找左孩子的最右节点
    //没左孩子,找孩子是父亲的右节点的祖先
    Self& operator--()
    {
        if (_node->_left)
        {
            _node = _node->_left;

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

            while (parent && parent->_left == _node)
            {
                _node = parent;
                parent = _node->_parent;
            }

            _node = parent;
        }

        return *this;
    }

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

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

};

四、问题4

解决完以上三个问题以后,迭代器也实现完成,接下来我们就可以来看看库中的库中Insert插入是怎么玩的了,其实大部分实现是相同的,具体看之前的红黑树相关文章,不同的是库中Insert的返回值
在这里插入图片描述
无论是set还是map的insert的返回值都是一个键值对,first是一个迭代器,second是一个bool类型,这意味着红黑树中的insert也是一样,因为set和map在库中是红黑树封装的,所以如果树中存在该key值,返回key所在节点的迭代器,如果不存在该key值,那么插入key,也返回该新增节点的迭代器,bool类型则是判断是否成功插入,如果存在则是插入失败,不存在则说明是新增,则插入成功,这说明insert函数还具有查找功能

基于此性质,引出了map的计数功能,可以通过insert返回的迭代器查看是否有key值,如果不存在则插入,将value值赋值为1,如果key已经存在,则通过insert返回的迭代器将value++,以此实现计数功能,所以map实现了operator[],用来计数

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

五、封装代码

map.h

#include "RBTree.h"

namespace Tlzns
{
	template<class K, class V>
	class map
	{

	public:
		struct KeyOfT
		{
			const K& operator()(const pair<K,V>& data)
			{
				return data.first;
			}
		};

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


		pair<iterator, bool> insert(const pair<K, V>& data)
		{
			return _t.Insert(data);
		}


		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 = insert(make_pair(key, V()));
			//return  ret.first->second;

			return insert(make_pair(key, V())).first->second;
		}


	private:

		RBTree<K, pair<const K, V>, KeyOfT>  _t;
	};
}

set.h

#include "RBTree.h"

namespace Tlzns
{
	template<class K>
	class set
	{
	public:
		struct KeyOfT
		{
			const K& operator()(const K& data)
			{
				return data;
			}
		};
		
		typedef typename RBTree<K, K, KeyOfT>::const_iterator iterator;
		typedef typename RBTree<K, K, KeyOfT>::const_iterator const_iterator;


		pair<iterator, bool> insert(const K& data)
		{
			return _t.Insert(data);
		}

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

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

	private:

		RBTree<K, K, KeyOfT> _t;
	};
}

RBTree.h

#include <iostream>
using namespace std;

enum Color
{
	Red,
	Black
};

template <class T>
struct TreeNode
{
	TreeNode(const T& data)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _data(data)
		, _col(Red)
	{}

	TreeNode* _left;
	TreeNode* _right;
	TreeNode* _parent;
	T _data;
	Color _col;
};


template <class T, class Ref, class Ptr>
struct _treeiterator
{
	typedef TreeNode<T> Node;

	typedef _treeiterator<T, T&, T*> iterator;
	typedef _treeiterator<T, Ref, Ptr> Self;

	Node* _node;

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

	_treeiterator(const iterator& x)
		:_node(x._node)
	{}

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

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

	//有右孩子,找右孩子的最左节点
	//没右孩子,找孩子是父亲的左节点的祖先
	Self& operator++()
	{
		if (_node->_right)
		{
			_node = _node->_right;

			while (_node->_left)
			{
				_node = _node->_left;
			}

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

			_node = parent;

		}

		return *this;
	}

	//有左孩子,找左孩子的最右节点
	//没左孩子,找孩子是父亲的右节点的祖先
	Self& operator--()
	{
		if (_node->_left)
		{
			_node = _node->_left;

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

			while (parent && parent->_left == _node)
			{
				_node = parent;
				parent = _node->_parent;
			}

			_node = parent;
		}

		return *this;
	}

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

};




template <class K, class T, class KeyOfT>
class RBTree
{
	typedef TreeNode<T> Node;

public:

	//typedef _treeiterator<T> iterator;

	typedef _treeiterator<T, T&, T*> iterator;
	typedef _treeiterator<T, const T&, const T*> const_iterator;


	iterator begin()
	{
		if (_root == nullptr)
		{
			return nullptr;
		}

		Node* cur = _root;

		while (cur->_left)
		{
			cur = cur->_left;
		}

		return cur;
	}


	iterator end()
	{
		return nullptr;
	}


	const_iterator begin()const
	{
		if (_root == nullptr)
		{
			return nullptr;
		}

		Node* cur = _root;

		while (cur->_left)
		{
			cur = cur->_left;
		}

		return cur;
	}

	const_iterator end()const
	{
		return nullptr;
	}


	//pair<iterator, bool> Insert(const T& data)

	pair<Node*, bool> Insert(const T& data)
	{
		if (_root == nullptr)
		{
			_root = new Node(data);
			_root->_col = Black;
			return make_pair(_root, true);
		}
		KeyOfT kof;

		Node* cur = _root;
		Node* parent = nullptr;

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

		Node* newnode = new Node(data);

		if (kof(parent->_data) > kof(data))
		{
			cur = newnode;
			parent->_left = cur;
			cur->_parent = parent;
		}
		else
		{
			cur = newnode;
			parent->_right = cur;
			cur->_parent = parent;
		}


		while (parent && parent->_col == Red)
		{
			if (parent->_col == Black)
			{
				break;
			}

			//parent是红色,需要先找祖父,再寻找uncle
			Node* grandparent = parent->_parent;
			Node* uncle = nullptr;



			//parent在左 uncle在右
			if (grandparent->_left == parent)
			{
				uncle = grandparent->_right;


				//uncle存在且为红色
				if (uncle && uncle->_col == Red)
				{
					parent->_col = Black;
					uncle->_col = Black;
					grandparent->_col = Red;

					//继续向上更新
					cur = grandparent;
					parent = cur->_parent;
				}
				//uncle存在且为黑色或者uncle不存在
				else
				{
					//cur在左,右单旋
					if (cur == parent->_left)
					{
						RotateR(grandparent);

						parent->_col = Black;
						grandparent->_col = Red;

						break;
					}
					//cur在右,双旋
					else
					{
						RotateL(parent);
						RotateR(grandparent);

						cur->_col = Black;
						grandparent->_col = Red;

						break;
					}
				}


			}
			//parent在右 uncle在左
			else
			{
				uncle = grandparent->_left;

				//uncle存在且为红色
				if (uncle && uncle->_col == Red)
				{
					parent->_col = uncle->_col = Black;
					grandparent->_col = Red;

					cur = grandparent;
					parent = cur->_parent;
				}
				//uncle存在且为黑色或uncle不存在
				else
				{
					//cur在右,左单旋
					if (cur == parent->_right)
					{
						RotateL(grandparent);

						parent->_col = Black;
						grandparent->_col = Red;

						break;
					}
					//cur在左,双旋
					else
					{
						RotateR(parent);
						RotateL(grandparent);

						cur->_col = Black;
						grandparent->_col = Red;

						break;
					}

				}

			}


		}

		_root->_col = Black;
		return make_pair(newnode, true);
	}

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

		parent->_right = subRL;
		subR->_left = parent;

		Node* parentparent = parent->_parent;

		if (subRL)
			subRL->_parent = parent;

		parent->_parent = subR;

		if (parent == _root)
		{
			subR->_parent = nullptr;
			_root = subR;
		}
		else
		{
			subR->_parent = parentparent;

			if (parentparent->_left == parent)
			{
				parentparent->_left = subR;
			}
			else
			{
				parentparent->_right = subR;
			}
		}
	}

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

		parent->_left = subLR;
		subL->_right = parent;

		Node* parentparent = parent->_parent;

		if (subLR)
		{
			subLR->_parent = parent;
		}
		parent->_parent = subL;

		if (parent == _root)
		{
			subL->_parent = nullptr;
			_root = subL;
		}
		else
		{
			subL->_parent = parentparent;

			if (parentparent->_left == parent)
			{
				parentparent->_left = subL;
			}
			else
			{
				parentparent->_right = subL;
			}
		}
	}


	void InOrder()
	{
		_InOrder(_root);
		cout << endl;
	}

	bool Isbalance()
	{
		if (_root == nullptr)
		{
			return true;
		}

		if (_root->_col == Red)
		{
			return false;
		}

		size_t reference = 0;

		Node* cur = _root;

		while (cur)
		{
			if (cur->_col == Black)
			{
				reference++;
			}
			cur = cur->_left;
		}

		return _Isbalance(_root, reference, 0);
	}



private:

	void _InOrder(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
		KeyOfT kof;
		_InOrder(root->_left);
		cout << kof(root->_data) << " ";
		_InOrder(root->_right);
	}

	bool _Isbalance(Node* root, size_t reference, size_t bnum)
	{
		if (root == nullptr)
		{
			if (bnum != reference)
			{
				cout << "每条路径黑色节点个数不同" << endl;
				return false;
			}
			return true;
		}

		if (root->_col == Red)
		{
			if (root->_parent->_col != Black)
			{
				cout << "出现连续的红色节点" << endl;
				return false;
			}
		}
		else
		{
			bnum++;
		}

		return _Isbalance(root->_left, reference, bnum) && _Isbalance(root->_right, reference, bnum);
	}


	Node* _root = nullptr;
};

此篇文章主要讲map和set用RBTree封装的思路,学习库中的玩法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值