简单实现map和set

目录

1 红黑树

1.1 红黑树迭代器

1.2 树

2 set

3 map


1 红黑树

1.1 红黑树迭代器

        难点是Increament和DeIncreament函数,用来实现迭代器的加加减减。下面讲解一下Increament的思路,DeIncreament思路与其大致思路相同,不过就是一个相反的关系。

        红黑树按照中序遍历,当前节点加加就应该要到当前节点的右子树找最左节点,但是右节点有可能为null。因此就需要分右节点是否为空两种情况。

        当右节点不为空,到右子树找最左节点。当右节点为空,说明以该节点为根的子树已经遍历完了,向上找父节点。如果父节点的左子树是当前节点,那么该父节点就是下一个节点。否则就是以父节点为根的子树也遍历完了,把父节点看作当前节点继续看其父节点,直到一个父节点的左子树是当前节点。

	template<class T, class Ref, class Ptr>
	class RBTreeIterator
	{
		typedef RBTreeNode<T> Node;
		typedef Node* pNode;
		typedef RBTreeIterator<T, Ref, Ptr> self;
	public:
		RBTreeIterator(const pNode& pnode) :_pNode(pnode) {}
		Ref operator*()
		{
			return _pNode->val;
		}
		Ptr operator->()
		{
			return &_pNode->val;
		}
		self& operator++()
		{
			Increament();
			return *this;
		}
		self operator++(int)
		{
			self temp = *this;
			Increament();
			return temp;
		}
		self& operator--()
		{
			DeIncreament();
			return *this;
		}
		self operator--(int)
		{
			self temp = *this;
			DeIncreament();
			return temp;
		}
		bool operator==(const self& p)const
		{
			return _pNode == p._pNode;
		}
		bool operator!=(const self& p)const
		{
			return _pNode != p._pNode;
		}
	private:
		void Increament()
		{
			if (_pNode->right)
			{
				Node* cur = _pNode->right;
				while (cur->left)
				{
					cur = cur->left;
				}
				_pNode = cur;
			}
			else
			{
				Node* cur = _pNode;
				Node* parent = _pNode->parent;
				while (parent && parent->right == cur)
				{
					cur = parent;
					parent = parent->parent;
				}
				_pNode = parent;
			}
		}
		void DeIncreament()
		{
			if (_pNode->left)
			{
				Node* cur = _pNode->left;
				while (cur->right)
				{
					cur = cur->right;
				}
				_pNode = cur;
			}
			else
			{
				Node* cur = _pNode;
				Node* parent = _pNode->parent;
				while (parent && parent->left == cur)
				{
					cur = parent;
					parent = parent->parent;
				}
				_pNode = parent;
			}
		}
	private:
		pNode _pNode;
	};

1.2 树

        树的模板参数除了ValueType表示要存数据的类型,还有一个参数KeyOfValue表示传入一个仿函数。因为map的数据是一个pair键值对,数据比较时要比较的是第一个键的值,不能使用pair原生的比较方式,我们使用仿函数对其处理,由此可以做到map和set都可以使用这个树来实现。同时还把begin和end接口实现在树里,map和set的begin和end调用该接口就行了。

	template<class T , class K>
	class RBTree
	{
	public:
		typedef RBTreeNode<T> Node;
		typedef Node* pNode;
		typedef RBTreeIterator<T, T&, T*> iterator;
	public:
		RBTree():_root(nullptr) {}
		iterator begin()
		{
			pNode cur = _root;
			while (cur->left)
			{
				cur = cur->left;
			}
			return iterator(cur);
		}
		iterator end()
		{
			return iterator(nullptr);
		}
		pair<iterator, bool> Insert(const T& data)
		{
			if (_root == nullptr)
			{
				_root = new Node(data);
				_root->color = BLACK;
				return std::make_pair(iterator(_root), true);
			}
			pNode cur = _root;
			pNode parent = nullptr;
			K k;
			while (cur)
			{
				parent = cur;
				if (k(cur->val) < k(data))
					cur = cur->right;
				else if (k(cur->val) > k(data))
					cur = cur->left;
				else
					return std::make_pair(iterator(cur), false);
			}
			cur = new Node(data);
			pNode newNode = cur;
			if (k(parent->val) > k(data))
				parent->left = cur;
			else if (k(parent->val) < k(data))
				parent->right = cur;
			else
				assert(false);

		    //控制平衡
            。。。。。。
	    }
	    bool IsBalance();
    private:
	    bool _isBanlance(pNode cur, int banchmark, int blacknum);
	    void RotateL(pNode parent);
	    void RotateR(pNode parent);
    private:
	    pNode _root;
    };

2 set

        我们把树的接口做好,实现set类就很简单了。需要注意的就是SetKeyOfT中仿函数的实现了,set中只存储一个值,直接原样返回就行了。

#pragma once
#include "RBTree.h"
namespace lwh  // 同上
{
	template<class T>
	class set 
	{
		struct SetKeyOfT
		{
			const T& operator()(const T& data) { return data; }
		};
	public:
		typename typedef RBTreeIterator<T, T&, T*> iterator;
		set() :_t() {}
		iterator begin()
		{
			return _t.begin();
		}
		iterator end()
		{
			return _t.end();
		}
		bool Insert(const T& data)
		{
			return _t.Insert(data).second;
		}
	private:
		RBTree<T, SetKeyOfT> _t;
	};
}

3 map

        同样的map由于存储的键值对,就需要特别设置仿函数返回键值对中的键。还有就是[]符号重载,该符号先是在树中插入(以中括号中的内容为键),然后返回该键对应的内容。

#pragma once
#include <iostream>
namespace lwh
{
	template<class K,class T>
	class map
	{
		struct MapKeyOfT
		{
			const T& operator()(const std::pair<K, T>& data) { return data.first; }
		};
	public:
		map() :_t() {}
		typename typedef RBTree<std::pair<K, T>, MapKeyOfT>::iterator iterator;
		iterator begin()
		{
			return _t.begin();
		}
		iterator end()
		{
			return _t.end();
		}
		pair<iterator, bool> Insert(const std::pair<K, T>& data)
		{
			return _t.Insert(data);
		}
		T& operator[](const K& key)
		{
			auto ret = _t.Insert(make_pair(key, T()));
			return ret.first->second;
		}
	private:
		RBTree<std::pair<K,T>, MapKeyOfT> _t;
	};
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值