C++ STL 容器 map 常见用法总结
map 是 C++ STL 中的关联容器,用于存储 键值对(key-value)。
它的特点是:
-
每个键
key唯一 -
会按照
key自动排序(默认从小到大) -
可以通过
key快速查找对应的value -
底层通常是红黑树
-
插入、删除、查找的时间复杂度通常是 O(log n)
map 常用于:
-
统计次数
-
建立映射关系
-
离散化辅助
-
记录状态
-
字符串 / 大整数 / 坐标映射
1. 头文件与定义
基本定义
表示:
-
键类型是
int -
值类型也是
int
也可以定义其他类型:
2. map 的基本特点
例如:
遍历时会按 key 升序输出:
说明:
-
map存的是键值对 -
排序依据是
key -
key不能重复,重复赋值会覆盖原值
3. 元素访问
3.1 用 [] 访问
注意
如果访问一个不存在的键:
会发生两件事:
-
自动创建键
5 -
值默认初始化为
0(如果 value 是int)
所以这句之后,mp 里就有了一个 {5, 0}。
3.2 用 at() 访问
特点:
-
键存在时正常访问
-
键不存在时会报异常
-
不会像
[]那样自动插入新元素
比赛里一般更常用 []。
4. 常用操作
4.1 插入元素
- 方法 1:直接赋值
- 方法 2:
insert()
注意:
-
如果键已存在,
insert()不会覆盖原值 -
[]赋值会覆盖原值
例如:
最终:
4.2 删除元素
- 按键删除
删除键为 1 的键值对。
- 按迭代器删除
4.3 查找元素
说明:
-
it->first是键 -
it->second是值
4.4 count():判断键是否存在
对于 map:
-
存在返回
1 -
不存在返回
0
因为键不会重复。
4.5 size():元素个数
4.6 empty():判断是否为空
4.7 clear():清空
5. 遍历 map
5.1 范围 for
5.2 迭代器遍历
for (auto it = mp.begin(); it != mp.end(); it++) {
cout << it->first << " " << it->second << endl;
}
5.3 结构化绑定(C++17)
6. 自动排序
map 默认按键从小到大排序。
map<int, string> mp;
mp[3] = "c";
mp[1] = "a";
mp[2] = "b";
for (auto [k, v] : mp) {
cout << k << " " << v << endl;
}
输出:
7. 统计次数
这是 map 最经典的用途。
结果:
输出统计结果:
8. 统计字符出现次数
string s = "abacaba";
map<char, int> cnt;
for (char c : s) cnt[c]++;
for (auto [ch, num] : cnt) {
cout << ch << " " << num << endl;
}
9. 字符串映射
比赛里常用于:
-
单词计数
-
姓名映射编号
-
字符串状态记录
10. map<pair<int,int>, int> 的用法
有些题会把坐标、状态二元组作为键。
这在以下场景常见:
-
网格状态
-
坐标压缩
-
二维状态记录
11. lower_bound() 和 upper_bound()
和 set 类似,map 也支持按键查找范围。
lower_bound(x)
返回第一个 key >= x 的位置。
auto it = mp.lower_bound(5);
if (it != mp.end()) {
cout << it->first << " " << it->second << endl;
}
upper_bound(x)
返回第一个 key > x 的位置。
auto it = mp.upper_bound(5);
if (it != mp.end()) {
cout << it->first << " " << it->second << endl;
}
12. 降序 map
默认升序,如果想按键降序:
示例:
map<int, int, greater<int>> mp;
mp[3] = 30;
mp[1] = 10;
mp[2] = 20;
for (auto [k, v] : mp) {
cout << k << " " << v << endl;
}
输出:
13. 常见应用场景
13.1 计数器
13.2 建立编号映射
13.3 判重
不过纯判重时通常 set 更合适。
13.4 记录状态值
适合键值不连续、范围很大时。
14. 常见注意事项
14.1 mp[x] 会自动创建元素
这是最容易忽略的点。
执行后,mp 中会多出:
如果你只是想判断是否存在,建议用:
14.2 key 不能重复
最终只保留:
后面的赋值会覆盖前面的值。
14.3 find() 返回迭代器,不是值
14.4 map 不支持下标位置访问
错误理解:
map 不是顺序容器,不能按“第几个元素”访问。
14.5 遍历时修改键是不允许的
map 中键值对的键部分不能直接改。
错误理解:
这是不允许的。
如果要改键,通常做法是:
-
删除旧键
-
插入新键
15. 蓝桥杯常见模板
15.1 统计次数模板
15.2 字符统计模板
15.3 字符串编号模板
15.4 遍历输出模板
16. 一份完整示例代码
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
map<string, int> mp;
mp["apple"] = 3;
mp["banana"] = 5;
mp["apple"]++;
for (auto [fruit, cnt] : mp) {
cout << fruit << " " << cnt << endl;
}
if (mp.count("apple")) {
cout << "apple 存在,数量为 " << mp["apple"] << endl;
}
mp.erase("banana");
return 0;
}
17. 必背内容
定义
常用操作
mp[key] = value; // 赋值 / 插入
mp.erase(key); // 删除
mp.find(key); // 查找
mp.count(key); // 是否存在
mp.lower_bound(key); // 第一个 >= key
mp.upper_bound(key); // 第一个 > key
mp.size(); // 元素个数
mp.empty(); // 判空
mp.clear(); // 清空
遍历
18. set 和 map 的区别
| 容器 | 存储内容 | 是否有值 value |
是否自动排序 | 键是否唯一 |
|---|---|---|---|---|
set |
只有元素本身 | 否 | 是 | 是 |
map |
键值对 key-value |
是 | 是(按 key) | 是 |
你可以这样理解:
-
set:只关心“这个元素在不在” -
map:关心“这个键对应什么值”
19. 总结
map 的核心特点:
-
存键值对
-
键唯一
-
按键自动排序
-
查找 / 插入 / 删除效率高
蓝桥杯中最常见的几个方向:
-
计数
-
映射
-
状态记录
-
字符串编号
-
有序键查询