在 C++ STL 中,map 是有序键值对(key-value)关联容器 ,它的核心特点是键唯一、自动排序、高效查找,是开发中处理映射关系(如字典、配置、索引)最常用的容器之一。
这篇笔记会从核心特性、头文件、常用操作、底层原理、适用场景、避坑指南 全面掌握 map。
一、map 核心特性(必记)
- 存储结构 :以键值对(pair<key, value>) 为单元存储。
- 键的规则 :键(key)唯一不可重复,值(value)可重复。
- 排序规则 :默认按照键(key)升序排序(底层红黑树自动排序)。
- 访问方式 :支持通过键快速访问值 (
map[key])。 - 底层实现 :红黑树(平衡二叉搜索树)。
- 效率 :
- 查找、插入、删除:O(log n)(对数时间,效率极高)。
- 与 unordered_map 区别 :
map:有序,底层红黑树,查找 / 插入稳定。unordered_map:无序,底层哈希表,查找更快(O (1))。
二、必备头文件
使用 map 必须包含以下头文件:
cpp
#include <map> // map 核心头文件
#include <iostream>
using namespace std;
三、map 常用操作(完整代码示例)
1. 定义与初始化
map 模板参数:map<key类型, value类型>
cpp
// 1. 空map
map<int, string> m1;
// 2. 初始化列表(C++11及以上)
map<int, string> m2 = {{1, "张三"}, {2, "李四"}, {3, "王五"}};
// 3. 拷贝初始化
map<int, string> m3(m2);
2. 插入元素(4 种常用方式)
map 插入会自动去重、自动排序。
cpp
map<int, string> m;
// 方式1:[] 赋值(最简单,若键已存在则覆盖值)
m[1] = "张三";
m[2] = "李四";
// 方式2:insert + pair(推荐,键已存在则插入失败,不覆盖)
m.insert(pair<int, string>(3, "王五"));
// 方式3:insert + make_pair(简化版)
m.insert(make_pair(4, "赵六"));
// 方式4:emplace(C++11,直接构造,效率最高)
m.emplace(5, "孙七");
- 访问元素
cpp
map<int, string> m = {{1, "张三"}, {2, "李四"}};
// 方式1:[] 访问(键不存在会自动插入默认值)
cout << m[1] << endl; // 输出:张三
// 方式2:at() 访问(键不存在会抛异常,更安全)
cout << m.at(2) << endl; // 输出:李四
// 方式3:通过迭代器访问
auto it = m.find(1);
if (it != m.end()) {
cout << it->first << ":" << it->second << endl;
// first=键,second=值
}
4. 查找元素(最常用)
find(key):找到返回迭代器,没找到返回 end()。
cpp
map<int, string> m = {{1, "张三"}, {2, "李四"}};
// 查找键为 2 的元素
auto it = m.find(2);
if (it != m.end()) {
cout << "找到:" << it->second << endl;
} else {
cout << "未找到" << endl;
}
// 统计键的个数(map 键唯一,结果只有 0 或 1)
cout << m.count(1) << endl; // 输出 1
- 删除元素
cpp
map<int, string> m = {{1, "张三"}, {2, "李四"}, {3, "王五"}};
// 方式1:按键删除
m.erase(2); // 删除键为 2 的元素
// 方式2:按迭代器删除
auto it = m.find(3);
m.erase(it);
// 方式3:清空所有元素
m.clear();
- 容量操作
cpp
map<int, string> m = {{1, "张三"}, {2, "李四"}};
// 获取元素个数
cout << m.size() << endl; // 输出 2
// 判断是否为空
cout << m.empty() << endl; // 输出 0(false)
- 遍历元素(3 种方式)
cpp
map<int, string> m = {{1, "张三"}, {2, "李四"}, {3, "王五"}};
// 方式1:迭代器遍历
for (auto it = m.begin(); it != m.end(); ++it) {
cout << it->first << ":" << it->second << endl;
}
// 方式2:范围for(最简洁,推荐)
for (auto& p : m) { // p 是 pair<int, string>
cout << p.first << ":" << p.second << endl;
}
// 方式3:auto + 结构化绑定(C++17,最优雅)
for (auto [key, val] : m) {
cout << key << ":" << val << endl;
}
8. 自定义排序(改变默认升序)
默认 map 按键升序 ,可改为降序:
cpp
// 降序 map
map<int, string, greater<int>> m = {{1, "张三"}, {2, "李四"}};
四、map 底层原理
map 底层是红黑树(一种自平衡二叉搜索树):
- 所有元素按照键(key) 排序。
- 插入 / 删除 / 查找都能保持树平衡,效率稳定在 O(log n)。
- 因为是红黑树,迭代器遍历是有序的。
五、适用场景
优先使用 map 的场景:
- 需要键值映射(如 ID→姓名、单词→解释、配置项→值)。
- 需要按键有序遍历。
- 需要高效查找、插入、删除(百万级数据无压力)。
不建议使用 map 的场景:
- 追求极致查找速度 → 用
unordered_map(哈希表)。 - 键允许重复 → 用
multimap。
六、常见坑点(避坑指南)
- 键不能重复 :重复插入同一个键,insert 会失败,[] 会覆盖值。
- [] 访问危险 :使用
m[key]时,如果key 不存在 ,会自动插入默认值。 - 迭代器失效 :
map插入 / 删除操作,除被删除节点外,其他迭代器都不失效。 - 排序只看键 :
map只根据 key 排序,与 value 无关。 - 不能修改键 :键(
it->first)是只读的,修改会破坏红黑树结构。
总结
map是有序、键唯一的键值对容器,底层红黑树。- 核心操作:
[]访问、insert插入、find查找、erase删除。 - 查找 / 插入 / 删除效率:O(log n)。
- 适用:需要映射关系 + 有序 + 稳定效率的场景。
- 与
unordered_map互补:有序用map,极速查找用unordered_map。