关联容器支持高效的关键字查找和访问.两个主要的关联容器是map和set(其他的都是这两个的变种).
map和multimap定义在头文件map中.set和multise定义在头文件set中.无序容器定义在头文件unordered_map和unordered_set中.
11.1使用关联容器
map的元素类型为pair,包含两个部分,key和value,即键值对.定义map时需要指定键的类型以及值的类型.
map中不允许有相同的键名(关键字).
从map中提取元素时是得到一个pair类型的对象,可以使用first和second(数据成员)来获取map的键和值:
set和map不一样的是set不存在值,而是只有键名(关键字),并且同样不允许关键字重复.
由于set元素没有值,只有关键字,因此通过迭代获取set元素只需要直接解引用就可以(参考上例).
11.2关联容器概述
关联容器不支持顺序容器的位置相关的操作,例如push_front,push_back.因为关联容器的元素是根据关键字存储的,因此只能插入(insert).
11.2.1定义关联容器
初始化map可以参考我上面的代码,但是map和set都不允许有重复的关键字,但是编译器不会报错.重复定义的关键字不会存入map或set中.multimap或是multiset和maph,set不同的是它们可以有重复的关键字,因此初始化的时候就可以有多个相同的关键字.
11.2.2关键字类型的要求
关联有序容器(map,set,multimap,multiset)的关键字;类型必须有定义元素比较的方法,如果关键字是自己定义的类类型,那么就需要自己定义比较方法(重载比较运算符)并且关键字类型需严格弱序,
严格弱序:
两个关键字不能同时小于等于对方.
a小于等于b,b小于等于c,那么a小于等于c.
a等价于b,b等价于c,那么a等价于c.
(我感觉这种规定都挺直觉的,不用特地记起来)
如果用的是标准库提供的那就无需麻烦.因为关联有序容器是默认按照关键字升序来排序的,因此我们上面的代码用迭代器遍历map,set时可以看到关键字确实是按照升序打印出来的.
11.2.3 pair类型
pair是一个模板类型,它定义在头文件utility中.pair保存两个数据成员,两个数据的类型可以不一样.包含两个成员变量(first,second)分别为前后两个数据成员.
11.3关联容器操作
关联容器定了类型别名:
对于set来说,key_type和value_type是一样的.
11.3.1关联容器迭代器
迭代map会得到pair,通过访问first和second来获取键和值,其中关键字是无法修改的,但是可以修改值.set的迭代器是const,因此不能通过set迭代器来修改set元素.
我们通常不会对关联容器使用泛型算法,就是因为上面的原因.
11.3.2添加元素
insert,emplace返回的值依赖于容器类型和参数 ,对于不包含重复元素的容器,添加单一元素的insert和emplace返回一个pair,first指向具有给定关键字的元素,second指向bool,来表示插入成功或是失败(容器中已经有相同的关键字的时候返回false).
而向multimap或multiset插入时,insert指向新元素的迭代器,因为插入永远是成功的(可以包含相同的关键字)
11.3.3删除元素
11.3.4 map的下标操作
使用[关键字]来访问map不会检查map是否含有关键字,如果直接访问或是操作未添加的关键字,那么会自动添加上此关键字,再进行默认初始化,最后再访问或是操作.使用at(关键字)则会检查,如果容器内没有关键字则会抛出异常.
使用下标访问对象,会直接返回值,而使用迭代器则会返回pair.
11.3.5访问元素
下表中lower_bound和upper_bound不适用于无序容器.
下标和at只适用于非const的map和unordered_map.
在multimap或是multiset中有多个相同关键字时,它们会被放置在相邻位置.因此我们查询multimap或multiset时需要使用find和count.
11.4无序容器
unordered开头的容器为无序容器,与有序容器不同的是,无序关联容器使用的是哈希函数和关键字类型的==运算符,而不是使用比较运算符来排序关键字,因此无序容器维护元素的序列代价远小于有序列表.因此,如果我们使用自定义类类型作为关键字则一个提供自己的哈希模板版本.
若是无需排序关键字,那么使用unordered_map/unordered_set则可以获得更快的查找数据(或许使用map超时的力扣题改用unordered_map就可以通过的呢)