一.map的结构特征
1.基本概念
map是一个模板类。它的底层仍旧是一棵不允许重复 的红黑树(平衡二叉搜索树),但每个节点存在两个值(键值对 ),一个是key,另一个是value 。其中,key参与二叉树增删查改,决定了二叉树的结构,所以无法更改。但value是可以改变的。

其中模板参数Key就是key的类型,T就是value的类型。
那么,使用什么存储key和value呢?答案是pair类模板。
2.节点里的pair类模板
存在两个成员变量:first和second,以及两个模板参数:T1和T2。T1代表first(key)的类型,T2代表second(value)的类型。


3.存储方式
用first存key,second存value。
二.insert的使用
菜鸟版:

要执行三个步骤,感觉好麻烦。
进阶版:
此时引入一个make_pair函数模板,将值传给make_pair,它会自动推出所传值类型,进而实例化出函数,最后通过该函数生成一个pair,并返回它。
这样就可以把创建pair和插入直接两步并作一步:

三.map的遍历
map是存在迭代器的,迭代器指向节点(map)的pair 。注意:指向节点的pair就代表指向节点了!!直接对迭代器解引用,并打印是行不通的,因为pair里是**同时存在key(first)和value(second)**的,c++并不支持一次性返回两个值,那么这时候it解引用返回谁呢?没办法确定。
想要打印,就需要限定一下,要打印pair里的哪个成员变量:

需要注意迭代器类型!!!!!!!当然,不想关注写成auto也是可以的。
四.operator[]的奥秘
1.浅谈功能和底层
在括号里给key(first),然后返回value(second)。


看样子只有查找,但在底层,[]同时具有插入,查找,修改三重功能

2.关于insert返回值(另一个pair)
在进行深入探讨前,请先留意一下,insert函数是有返回值的:

它也是一个pair类模板,但它和map底层树里pair存储的东西不同。
iterator(first):如果插入成功,就是指向新插入值节点的迭代器。 如果插入失败(已经存在与待插入值等值的节点),就是指向与key等值节点的迭代器。
bool(second):判断插入成功与否。

两种pair的区别

3.再探operator[]底层


上图insert里的参数,是节点的键值对(key和value),走的是隐式类型转换,将这对键值对转换为存储它们的pair。毕竟标准库里insert的形参就是存键值对的pair。
4.为何operator[]可以统计次数
我们来看下这个案例,并剖析能够统计次数的底层原理:

首先得明晰,我们将arr中每种水果的名字(first)和出现次数(second)作为pair的键值对。countMap代表,每个节点存储水果种类以及出现次数的红黑树。
在上面代码中,[]每遍历一个arr中的元素,就会先执行insert操作,假如碰到的水果是map里没有的,就会传该水果名,同时出现次数传的是int的缺省值0。插入完成后,返回的pair的first是指向刚刚插入节点的迭代器。然后用it接收该迭代器,it就指向完成插入后该水果对应的节点。
假如是map里有的,就插入失败,返回的pair的first就是指向同水果名节点的迭代器,然后一样的it接收迭代器,it就指向完成插入后该水果对应的节点。当然,出现次数也是该节点的插入次数,不再是缺省值了。
每执行完一次插入操作,就会返回it->second(出现次数),然后++;出现次数也就实现了更新,也就达到了计数的目的。


