cplusplus.com说map的[]、at()、find()、insert()的时间复杂度都是O(logn),因为map是用二叉搜索树实现的(复杂度O(logn)~O(n),平均O(logn)),而我容易误认为是类似数组[]的O(1)。
unordered_map(库文件同名,按hash值组织进buckets)相比map在根据key获得mapped value更快(平均O(1)),但是在iterator上效率更低。
set和unordered_set同理。(实现方式同上)
注意,入参在map中时,[]与at()都是返回映射值的引用;而入参不在map中时,[]会新建成员,at()会抛出异常。
项目中,要不是严苛追求效率,可以尽可能借助STL,有利于降低代码复杂度,提高可维护性和可阅读性,降低出错率
成员
[], at, insert, emplace,find的复杂度 | |
---|---|
map, set | 平均O(logn),最差O(n) |
unordered_map, unordered_set | 平均O(1),最差O(n) |
insert
key不存在时才插入,不会覆盖已有成员。有多种语法,详见cplusplus.com
mp.insert(make_pair(a, b));
emplace
与insert一样,只有key不存在时才插入,只是用法更简单。
mymap.emplace(‘x’,100);//这里key是字符x
iterator
map有序,迭代器一直有效;而unordered_map是无序的,元素根据hash值被组织进buckets从而可更快通过key获得value(平均O(1),最差O(n)),由于可能因为size等变化而rehash,iterator不是一直有效的。
变量的声明map<char,int>::iterator it = mymap.begin();
begin()->first是key,begin()->second是mapped value。
begin()可以用来修改它指向的内容,但cbegin()不可以。crbegin()同理。
rbegin()返回指向尾元素的反向迭代器。是有必要的,因为end()指向尾元素下一个的位置,begin()却不是指向首元素上一个的位置,所以反向遍历用rbegin()。(迭代器可以–,但不能取代这个便捷方式)
key type
map和unordered_map若使用vector<int, int>、pair<int, int>等自定义类型作为key type,则需要重载<>运算符,因为其成员都需要能互相比较。否则会报错call to implicitly-deleted default constructor。
unordered_set也也是,但set可以直接用vector作为key type,却不能用pair<int, int>