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封装的思路,学习库中的玩法

红黑树是一种自平衡的二叉搜索树,常用于实现关联容器map。 下面是C++代码示例,实现了一个红黑树类,可以用于实现map: ```c++ #include <iostream> using namespace std; enum Color {RED, BLACK}; template<typename K,typename V> class RBNode { public: K key; V value; Color color; RBNode<K,V> *left, *right, *parent; RBNode(): color(RED), left(nullptr), right(nullptr), parent(nullptr) {} RBNode(K k, V v): color(RED), key(k), value(v), left(nullptr), right(nullptr), parent(nullptr) {} RBNode(K k, V v, Color c): color(c), key(k), value(v), left(nullptr), right(nullptr), parent(nullptr) {} }; template<typename K,typename V> class RBTree { public: RBTree(); ~RBTree(); bool empty() const; int size() const; void clear(); void insert(const K& key,const V& value); bool find(const K& key); void remove(const K& key); void printTree() const; private: RBNode<K,V>* root; int count; void rotateLeft(RBNode<K,V>* node); void rotateRight(RBNode<K,V>* node); void fixup(RBNode<K,V>* node); RBNode<K,V>* minimum(RBNode<K,V>* node); void transplant(RBNode<K,V>* u, RBNode<K,V>* v); void removeNode(RBNode<K,V>* node); }; template<typename K,typename V> RBTree<K,V>::RBTree(): root(nullptr), count(0) {} template<typename K,typename V> RBTree<K,V>::~RBTree() { clear(); } template<typename K,typename V> bool RBTree<K,V>::empty() const { return count == 0; } template<typename K,typename V> int RBTree<K,V>::size() const { return count; } template<typename K,typename V> void RBTree<K,V>::clear() { while (root != nullptr) { removeNode(root); } count = 0; } template<typename K,typename V> void RBTree<K,V>::rotateLeft(RBNode<K,V>* node) { RBNode<K,V>* r = node->right; node->right = r->left; if (r->left != nullptr) r->left->parent = node; r->parent = node->parent; if (node->parent == nullptr) root = r; else if (node == node->parent->left) node->parent->left = r; else node->parent->right = r; r->left = node; node->parent = r; } template<typename K,typename V> void RBTree<K,V>::rotateRight(RBNode<K,V>* node) { RBNode<K,V>* l = node->left; node->left = l->right; if (l->right != nullptr) l->right->parent = node; l->parent = node->parent; if (node->parent == nullptr) root = l; else if (node == node->parent->right) node->parent->right = l; else node->parent->left = l; l->right = node; node->parent = l; } template<typename K,typename V> void RBTree<K,V>::fixup(RBNode<K,V>* node) { while (node->parent != nullptr && node->parent->color == RED) { if (node->parent == node->parent->parent->left) { RBNode<K,V>* uncle = node->parent->parent->right; if (uncle != nullptr && uncle->color == RED) { node->parent->color = BLACK; uncle->color = BLACK; node->parent->parent->color = RED; node = node->parent->parent; } else { if (node == node->parent->right) { node = node->parent; rotateLeft(node); } node->parent->color = BLACK; node->parent->parent->color = RED; rotateRight(node->parent->parent); } } else { RBNode<K,V>* uncle = node->parent->parent->left; if (uncle != nullptr && uncle->color == RED) { node->parent->color = BLACK; uncle->color = BLACK; node->parent->parent->color = RED; node = node->parent->parent; } else { if (node == node->parent->left) { node = node->parent; rotateRight(node); } node->parent->color = BLACK; node->parent->parent->color = RED; rotateLeft(node->parent->parent); } } } root->color = BLACK; } template<typename K,typename V> void RBTree<K,V>::insert(const K& key,const V& value) { RBNode<K,V>* node = new RBNode<K,V>(key, value); RBNode<K,V>* p = nullptr; RBNode<K,V>* q = root; while (q != nullptr) { p = q; if (node->key < q->key) q = q->left; else q = q->right; } node->parent = p; if (p == nullptr) root = node; else if (node->key < p->key) p->left = node; else p->right = node; count++; fixup(node); } template<typename K,typename V> bool RBTree<K,V>::find(const K& key) { RBNode<K,V>* node = root; while (node != nullptr) { if (key == node->key) return true; else if (key < node->key) node = node->left; else node = node->right; } return false; } template<typename K,typename V> void RBTree<K,V>::transplant(RBNode<K,V>* u, RBNode<K,V>* v) { if (u->parent == nullptr) root = v; else if (u == u->parent->left) u->parent->left = v; else u->parent->right = v; if (v != nullptr) v->parent = u->parent; } template<typename K,typename V> void RBTree<K,V>::removeNode(RBNode<K,V>* node) { if (node == nullptr) return; RBNode<K,V>* p = node->parent; bool isLeft = (p != nullptr && node == p->left); if (node->left == nullptr) { transplant(node, node->right); } else if (node->right == nullptr) { transplant(node, node->left); } else { RBNode<K,V>* s = minimum(node->right); RBNode<K,V>* sp = s->parent; isLeft = (s->parent != nullptr && s == s->parent->left); if (s->parent != node) { transplant(s, s->right); s->right = node->right; s->right->parent = s; } transplant(node, s); s->left = node->left; s->left->parent = s; s->color = node->color; } delete node; count--; if (isLeft) fixup(p->left); else fixup(p->right); } template<typename K,typename V> void RBTree<K,V>::remove(const K& key) { RBNode<K,V>* z = root; while (z != nullptr) { if (z->key == key) { removeNode(z); return; } else if (key < z->key) z = z->left; else z = z->right; } } template<typename K,typename V> RBNode<K,V>* RBTree<K,V>::minimum(RBNode<K,V>* node) { while (node->left != nullptr) node = node->left; return node; } template<typename K,typename V> void inOrder(RBNode<K,V>* node) { if (node == nullptr) return; if (node->left != nullptr) inOrder(node->left); cout << node->key << "(" << (node->color == RED ? "RED" : "BLACK") << ") "; if (node->right != nullptr) inOrder(node->right); } template<typename K,typename V> void RBTree<K,V>::printTree() const { inOrder(root); cout << endl; } int main() { RBTree<int,int> tree; tree.insert(1,2); tree.insert(2,3); tree.insert(3,4); tree.insert(4,5); tree.insert(5,6); tree.printTree(); cout << tree.find(3) << endl; tree.remove(3); tree.printTree(); return 0; } ``` 该示例中包含了插入、查找、删除等基本操作,并支持输出红黑树中所有节点及其颜色,可以用于验证红黑树的正确性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值