C++ map

有关背景和set的介绍可以点击了解C++ set,接下来介绍map

1. map的介绍

1. map 是关联容器,它按照特定的次序 ( 按照 key 来比较 ) 存储由键值 key 和值 value 组合而成的元素。
2. map 中,键值 key 通常用于排序和唯一地标识元素,而值 value 中存储与此键值 key 关联的内容。键值key 和值 value 的类型可能不同,并且在 map 的内部, key value 通过成员类型value_type绑定在一起,为其取别名称为 pair: typedef pair<const key, T> value_type;
3. 在内部, map 中的元素总是按照键值 key 进行比较排序的。
4. map 中通过键值访问单个元素的速度通常比 unordered_map 容器慢,但 map 允许根据顺序对元素进行直接迭代( 即对 map 中的元素进行迭代时,可以得到一个有序的序列 )
5. map 支持下标访问符,即在 [ ] 中放入 key ,就可以找到与 key 对应的 value
6. map 通常被实现为二叉搜索树 ( 更准确的说:平衡二叉搜索树 ( 红黑树 ))

2. map的使用

1. map的模板参数说明

key: 键值对中 key 的类型
T : 键值对中 value 的类型
Compare: 比较器的类型, map 中的元素是按照 key 来比较的,缺省情况下按照小于来比较,一般情况下( 内置类型元素 ) 该参数不需要传递,如果无法比较时 ( 自定义类型 ) ,需要用户自己显式传递比较规则( 一般情况下按照函数指针或者仿函数来传递 )
Alloc :通过空间配置器来申请底层空间,不需要用户传递,除非用户不想使用标准库提供的
空间配置器

2. map的构造

函数声明功能介绍
map()
构造一个空的 map

3. map的迭代器

函数声明
功能介绍
begin() end()
begin: 首元素的位置, end 最后一个元素的下一个位置
cbegin() cend()
begin end 意义相同,但 cbegin cend 所指向的元素不 能修改
rbegin() rend()
反向迭代器, rbegin end 位置, rend begin 位置,其 ++ -- 操作与 begin end 操作移动相反
crbegin() crend()
rbegin rend 位置相同,操作相同,但 crbegin crend 指向的元素不能修改

4. map的容量与元素访问

函数声明功能简介
bool empty ( ) const
检测map中的元素是否为空,是返回true,否则返回false
size_type size() const
返回 map 中有效元素的个数
mapped_type& operator[ ] (const key_type& k)
返回去 key 对应的 value
注意:在元素访问时,有一个与 operator[ ] 类似的操作 at()( 该函数不常用 ) 函数,都是通过
key 找到与 key 对应的 value 然后返回其引用,不同的是: key 不存在时, operator[ ] 用默认
value key 构造键值对然后插入,返回该默认 value at() 函数直接抛异常

5. map中元素的修改

函数声明
功能简介
pair<iterator,bool> insert (
const value_type& x )
map 中插入键值对 x ,注意 x 是一个键值 对,返回值也是键值对: iterator 代表新插入 元素的位置, bool 代表释放插入成功
void erase ( iterator position)
删除 position 位置上的元素
size_type erase ( const
key_type& x )
删除键值为 x 的元素
void erase ( iterator first,
iterator last )
删除 [first, last) 区间中的元素
void swap (
map<Key,T,Compare,Allocator>&
mp )
交换两个 map 中的元素
void clear ( )
map 中的元素清空
iterator find ( const key_type& x)
map 中插入 key x 的元素,找到返回该元 素的位置的迭代器,否则返回 end
const_iterator find ( const
key_type& x ) const
map 中插入 key x 的元素,找到返回该元 素的位置的 const 迭代器,否则返回 cend
size_type count ( const
key_type& x ) const
返回 key x 的键值在 map 中的个数,注意 map key 是唯一的,因此该函数的返回值 要么为 0 ,要么为 1 ,因此也可以用该函数来 检测一个 key 是否在 map

3.map的模拟实现

首先我们要使用红黑树进行封装map即可,如下是RBTree.cpp的文件,有关红黑树的详细介绍,可以点击了解C++ 红黑树

#include <iostream>
#include <vector>
using namespace std;
namespace rbtree
{
	enum Color
	{
		RED,
		BLACK,
	};
	//当我们需要存储键值对,那么T就是pair<K, V>
	//当我们只存储key值,那么T就是K
	template <class T>
	struct RBTreeNode
	{
		//构造函数
		RBTreeNode(T data)
			:_left(nullptr)
			, _right(nullptr)
			, _parent(nullptr)
			, _data(data)
			, _col(RED)
		{}
		//成员变量
		RBTreeNode* _left;
		RBTreeNode* _right;
		RBTreeNode* _parent;
		T _data;//节点数据
		Color _col;//颜色
	};
	//实现迭代器
	template<class T, class Ref, class Ptr>
	struct RBTreeIterator
	{
		typedef RBTreeNode<T> Node;
		typedef RBTreeIterator<T, Ref, Ptr> Self;
		Node* _node;
		//构造函数
		RBTreeIterator(Node* node)
			:_node(node)
		{}
		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;
		}
		//前置++
		Self& operator++()
		{
			//如果右子树不为空,说明该树未取完,要取右子树的最左结点
			if (_node->_right)
			{
				Node* left = _node->_right;
				while (left->_left)
				{
					left = left->_left;
				}
				_node = left;
			}
			//右子树为空,说明该树已经取完,要回到cur为左孩子的parent
			else
			{
				Node* cur = _node, * parent = cur->_parent;
				while (parent && parent->_right == cur)
				{
					cur = parent;
					parent = cur->_parent;
				}
				_node = parent;
			}
			return *this;
		}
		//后置++
		Self operator++(int)
		{
			Self old = new Self(_node);
			//如果右子树不为空,说明该树未取完,要取右子树的最左结点
			if (_node->_right)
			{
				Node* left = _node->_right;
				while (left->_left)
				{
					left = left->_left;
				}
				_node = left;
			}
			//右子树为空,说明该树已经取完,要回到cur为左孩子的parent
			else
			{
				Node* cur = _node, * parent = cur->_parent;
				while (parent && parent->_right == cur)
				{
					cur = parent;
					parent = cur->_parent;
				}
				_node = parent;
			}
			return old;
		}
		//前置--
		Self& operator--()
		{
			Self old = new Self(_node);
			//如果左子树不为空,说明该树未取完,要取左子树的最右结点
			if (_node->_left)
			{
				Node* right = _node->_left;
				while (right->_right)
				{
					right = right->_right;
				}
				_node = right;
			}
			//左子树为空,说明该树已经取完,要回到cur为右孩子的parent
			else
			{
				Node* cur = _node, * parent = cur->_parent;
				while (parent && parent->_left == cur)
				{
					cur = parent;
					parent = cur->_parent;
				}
				_node = parent;
			}
			return old;
		}
		//后置--
		Self operator--(int)
		{
			//如果左子树不为空,说明该树未取完,要取左子树的最右结点
			if (_node->_left)
			{
				Node* right = _node->_left;
				while (right->_right)
				{
					right = right->_right;
				}
				_node = right;
			}
			//左子树为空,说明该树已经取完,要回到cur为右孩子的parent
			else
			{
				Node* cur = _node, * parent = cur->_parent;
				while (parent && parent->_left == cur)
				{
					cur = parent;
					parent = cur->_parent;
				}
				_node = parent;
			}
			return *this;
		}
	};
	//前面的K用于传入key的类型,后面的T用于传入红黑树存储的数据类型。
	keyOfT仿函数,取出T对象中的key,用于比较
	template<class K, class T, class KeyOfT>
	class RBTree
	{
		typedef typename RBTreeNode<T> Node;
		typedef typename RBTreeIterator<T, T&, T*> iterator;
	public:
		//构造函数
		RBTree()
			:_root(nullptr)
		{} 
		//析构函数
		~RBTree()
		{
			Destroy(_root);
			_root = nullptr;
		}
		iterator begin()
		{
			Node* left = _root;
			while (left->_left)
			{
				left = left->_left;
			}
			return iterator(left);
		}
		iterator end()
		{
			return iterator(nullptr);
		}

		pair<iterator, bool> Insert(const T& data)
		{
			KeyOfT kot; 
			if (_root == nullptr)
			{
				_root = new Node(data);
				_root->_col = BLACK;
				return make_pair(iterator(_root), true);
			}
			//找位置插入
			Node* cur = _root, * parent = _root;
			while (cur)
			{
				if (kot(data) < kot(cur->_data))
				{
					parent = cur;
					cur = cur->_left;
				}
				else if (kot(data) > kot(cur->_data))
				{
					parent = cur;
					cur = cur->_right;
				}
				else
				{
					return make_pair(iterator(cur), false);
				}
			}
			cur = new Node(data);
			cur->_parent = parent;
			if (kot(data) < kot(parent->_data))
			{
				parent->_left = cur;
			}
			else
			{
				parent->_right = cur;
			}
			Node* ret = cur;
			//检查颜色(当连续出现两个红色时需要调整)
			while (parent && parent->_col == RED)
			{
				Node* grandparent = parent->_parent;
				if (parent == grandparent->_left)
				{
					Node* uncle = grandparent->_right;
					//如果uncle存在且为红,则将parent和uncle变黑,grandparent变红
					if (uncle && uncle->_col == RED)
					{
						parent->_col = uncle->_col = BLACK;
						grandparent->_col = RED;
						//继续向上检查
						cur = grandparent;
						parent = cur->_parent;
					}
					//uncle不存在或者为黑
					else
					{
						//将grandparent右旋,grandparent变为红,parent变为黑
						if (cur == parent->_left)
						{
							RotateR(grandparent);
							grandparent->_col = RED;
							parent->_col = BLACK;
						}
						//将parent左旋,grandparent右旋,将cur变为黑,grandparent变为红
						else
						{
							RotateL(parent);
							RotateR(grandparent);
							grandparent->_col =  RED;
							cur->_col = BLACK;
						}
						//此时最上面的结点为黑,可以直接结束
						break;
					}
				}
				else
				{
					Node* uncle = grandparent->_left;
					//如果uncle存在且为红,则将parent和uncle变黑,grandparent变红
					if (uncle && uncle->_col == RED)
					{
						parent->_col = uncle->_col = BLACK;
						grandparent->_col = RED;
						//继续向上检查
						cur = grandparent;
						parent = cur->_parent;
					}
					//uncle不存在或者为黑
					else
					{
						//将grandparent左旋,grandparent变为红,parent变为黑
						if (cur == parent->_right)
						{
							RotateL(grandparent);
							 grandparent->_col = RED;
							parent->_col = BLACK;
						}
						//将parent右旋,grandparent左旋,将cur变为黑,grandparent变为红
						else
						{
							RotateR(parent);
							RotateL(grandparent);
							grandparent->_col = RED;
							cur->_col = BLACK;
						}
						break;
					}
				}
			}
			//把根节点变为黑
			_root->_col = BLACK;
			return make_pair(iterator(ret), true);
		}

		bool _IsRBTree(Node* root, int count, int blacknum)
		{
			if (root == nullptr)
			{
				if (count != blacknum)
				{
					return false;
				}
				return true;
			}
			if (root->_col == BLACK)
			{
				count++;
			}
			return _IsRBTree(root->_left, count, blacknum) &&
				_IsRBTree(root->_right, count, blacknum);
		}
		bool IsRBTree()
		{
			if (_root->_col == RED)
			{
				return false;
			}
			int blacknum = 0;
			Node* cur = _root;
			while (cur)
			{
				if (cur->_col == BLACK)
				{
					blacknum++;
				}
				cur = cur->_left;
			}
			return _IsRBTree(_root, 0, blacknum);
		}
		void _InOrder(Node* root)
		{
			KeyOfT kot;
			if (root == nullptr)
			{
				return;
			}
			_InOrder(root->_left);
			cout << kot(root->_data) << " ";
			_InOrder(root->_right);
		}
		void InOrder()
		{
			_InOrder(_root);
			cout << endl;
		}
	private:
		void Destroy(Node* root)
		{
			if (root == nullptr)
			{
				return;
			}
			Destroy(root->_left);
			Destroy(root->_right);
			delete root;
		}
		//左单旋
		void RotateL(Node* parent)
		{
			Node* subR = parent->_right;
			Node* subRL = subR->_left;
			Node* grandparent = parent->_parent;
			parent->_right = subRL;
			if (subRL)
			{
				subRL->_parent = parent;
			}
			subR->_left = parent;
			parent->_parent = subR;
			if (parent == _root)
			{
				_root = subR;
			}
			else
			{
				if (grandparent->_left == parent)
					grandparent->_left = subR;
				else
					grandparent->_right = subR;
			}
			subR->_parent = grandparent;
		}
		//右单旋
		void RotateR(Node* parent)
		{
			Node* subL = parent->_left;
			Node* subLR = subL->_right;
			Node* grandparent = parent->_parent;
			parent->_left = subLR;
			if (subLR)
			{
				subLR->_parent = parent;
			}
			subL->_right = parent;
			parent->_parent = subL;
			if (parent == _root)
			{
				_root = subL;
			}
			else
			{
				if (grandparent->_left == parent)
					grandparent->_left = subL;
				else
					grandparent->_right = subL;
			}
			subL->_parent = grandparent;
		}
		//左右双旋
		void RotateLR(Node* parent)
		{
			Node* subL = parent->_left;
			Node* subLR = subL->_right;
			int bf = subLR->_bf;
			RotateL(subL);
			RotateR(parent);
		}
		//右左双旋
		void RotateRL(Node* parent)
		{
			Node* subR = parent->_right;
			Node* subRL = parent->_left;
			int bf = subRL->_bf;
			RotateR(subR);
			RotateL(parent);
		}
		Node* _root;
	};
};
map.cpp文件如下
#include "RBTree.cpp"
namespace lbk
{
	template <class K, class V>
	class map
	{
		struct MapKeyOfT
		{
			const K& operator()(const pair<K, V>& kv)
			{
				return kv.first;
			}
		};
		typedef typename rbtree::RBTreeIterator<pair<K, V>, pair<K, V>&, pair<K, V>*> iterator;

	public:
		iterator begin()
		{
			return _t.begin();
		}
		iterator end()
		{
			return _t.end();
		}
		pair<iterator, bool> insert(const pair<K, V>& kv)
		{
			return _t.Insert(kv);
		}
		V& operator[](const K& key)
		{
			pair<iterator, bool> ret = insert(make_pair(key, V()));
			return ret.first->second;
		}
		void InOrder()
		{
			_t.InOrder();
		}
	private:
		//前面的K用于传入key的类型,后面的T用于传入红黑树存储的数据类型。
		//红黑树中存储的值不可以改变,应加上const
		rbtree::RBTree<K, const pair<K, V>, MapKeyOfT> _t;
	};
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我要满血复活

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值