c++ map

map类的介绍

map的声明如下,Key就是map底层关键字的类型,T是map底层value的类型,set默认要求Key支持小于比较,如果不支持或者需要的话可以自行实现仿函数传给第⼆个模版参数,map底层存储数据的内存是从空间配置器申请的。⼀般情况下,我们都不需要传后两个模版参数。map底层是用红黑树实现,增删查改效率是O(logN) ,迭代器遍历是走的中序,所以是按key有序顺序遍历的。

cpp 复制代码
template < class Key, // map::key_type
 class T, // map::mapped_type
 class Compare = less<Key>, // map::key_compare
 class Alloc = allocator<pair<const Key,T> > // 
map::allocator_type
 > class map;

pair类型介绍

map底层的红黑树节点中的数据,使用pair存储键值对数据。

pair是将2个数据组合成一组数据,当需要这样的需求时就可以使用pair,map就是将key和value放在一起来保存。

map的插入在成功时会返回pair<新插入值所在的迭代器,true>,插入失败会返回pair<已存在跟key等值的迭代器,false>

cpp 复制代码
typedef pair<const Key, T> value_type;
template <class T1, class T2>
struct pair 
{
 typedef T1 first_type;
 typedef T2 second_type;
 T1 first;
 T2 second;
 
 pair(): first(T1()), second(T2())
 {}
 
 pair(const T1& a, const T2& b): first(a), second(b)
 {}
 
 template<class U, class V> 
 pair (const pair<U,V>& pr): first(pr.first), second(pr.second)
 {}
};
template <class T1,class T2>
inline pair<T1,T2> make_pair (T1 x, T2 y)
{
 return ( pair<T1,T2>(x,y) );
}

map的构造

map的迭代器支持正向和反向迭代遍历,遍历默认按key的升序顺序 ,因为底层是⼆叉搜索树,迭代器遍历走的中序;支持迭代器就意味着支持范围for,map支持修改value数据,不支持修改key数据,修改关键字数据,破坏了底层搜索树的结构。

cpp 复制代码
// empty (1) ⽆参默认构造 
explicit map (const key_compare& comp = key_compare(),
 const allocator_type& alloc = allocator_type());

// range (2) 迭代器区间构造 
template <class InputIterator>
 map (InputIterator first, InputIterator last,
 const key_compare& comp = key_compare(),
 const allocator_type& = allocator_type());

// copy (3) 拷⻉构造 
map (const map& x);

// initializer list (5) initializer 列表构造 
map (initializer_list<value_type> il,
 const key_compare& comp = key_compare(),
 const allocator_type& alloc = allocator_type());

map的增删查

map增接口,插入的pair键值对数据,跟set所有不同,但是查和删的接口只用关键字key跟set是完全类似的,不过find返回iterator,不仅仅可以确认key在不在,还找到key映射的value,同时通过迭代还可以修改value。

map在插入的时候只会检查key,不会检查value,key相同则不会插入。

cpp 复制代码
单个数据插⼊,如果已经key存在则插⼊失败,key存在相等value不相等也会插⼊失败 
pair<iterator,bool> insert (const value_type& val);

列表插⼊,已经在容器中存在的值不会插⼊ 
void insert (initializer_list<value_type> il);

迭代器区间插⼊,已经在容器中存在的值不会插⼊ 
template <class InputIterator>
void insert (InputIterator first, InputIterator last);

查找k,返回k所在的迭代器,没有找到返回end() 
iterator find (const key_type& k);

查找k,返回k的个数 
size_type count (const key_type& k) const;

删除⼀个迭代器位置的值 
iterator erase (const_iterator position);

删除k,k存在返回0,存在返回1 
size_type erase (const key_type& k);

删除⼀段迭代器区间的值 
iterator erase (const_iterator first, const_iterator last);

返回⼤于等k位置的迭代器 
iterator lower_bound (const key_type& k);

返回⼤于k位置的迭代器 
const_iterator lower_bound (const key_type& k) const;

map的数据修改

前⾯我提到map支持修改mapped_type数据,不支持修改key数据,修改关键字数据,破坏了底层搜索树的结构。

map第⼀个支持修改的方式时通过迭代器,迭代器遍历时或者find返回key所在的iterator修改,map 还有⼀个非常重要的修改接口operator[],但是operator[]不仅仅支持修改,还支持插⼊数据和查找数据,所以他是⼀个多功能复合接口,operator[]传key返回对应的value

需要注意从内部实现角度,map这里把我们传统说的value值,给的是T类型,typedef为 mapped_type。而value_type是红黑树结点中存储的pair键值对值。⽇常使⽤我们还是习惯将这⾥的 T映射值叫做value。

insert插入⼀个pair对象 :1.如果key已经在map中,插入失败,则返回⼀个pair对象,返回pair对象 first是key所在结点的迭代器,second是false 2.如果key不在在map中,插入成功,则返回⼀个pair对象,返回pair对象 first是新插⼊key所在结点的迭代器,second是true 也就是说无论插⼊成功还是失败,返回pair对象的first都会指向key所在的迭代器,那么也就意味着insert插⼊失败时充当了查找的功能,正是因为这⼀点,insert可以⽤来实现 operator[]

operator[]内部实现

cpp 复制代码
mapped_type& operator[] (const key_type& k)
{
 pair<iterator, bool> ret = insert({ k, mapped_type() });
 iterator it = ret.first;
 return it->second;
}

1、如果k不在map中 ,insert会插⼊k和mapped_type默认值,同时[]返回结点中存储

mapped_type值的引⽤,那么我们可以通过引用修改返映射值。所以[]具备了插⼊+修改功能

2、如果k在map中 ,insert会插⼊失败,但是insert返回pair对象的first是指向key结点的

迭代器,返回值同时[]返回结点中存储mapped_type值的引⽤,所以[]具备了查找+修改的功能

所以我们在使用operator[]需要注意该节点是否在map中存在,这影响了operator[]实现怎么样的操作。

相关推荐
浮生如梦_44 分钟前
Halcon基于laws纹理特征的SVM分类
图像处理·人工智能·算法·支持向量机·计算机视觉·分类·视觉检测
XiaoLeisj2 小时前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
励志成为嵌入式工程师3 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
捕鲸叉3 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer3 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
Peter_chq3 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
wheeldown4 小时前
【数据结构】选择排序
数据结构·算法·排序算法
记录成长java5 小时前
ServletContext,Cookie,HttpSession的使用
java·开发语言·servlet
前端青山5 小时前
Node.js-增强 API 安全性和性能优化
开发语言·前端·javascript·性能优化·前端框架·node.js
青花瓷5 小时前
C++__XCode工程中Debug版本库向Release版本库的切换
c++·xcode