Appearance
map系列容器详解
map系列容器是STL中核心的关联式容器,与set系列(值为关键字)不同,map以「键值对(key-value)」为存储单元,核心作用是实现“关键字映射”,即通过唯一的key(关键字)对应唯一的value(值),底层基于红黑树实现,支持高效的查找、插入和删除操作,是日常开发和算法题中常用的映射工具。
一、map核心特性
map系列容器主要分为两类:map 和 unordered_map,与set系列对应,二者核心区别在于「有序性」和「底层实现」,具体特性对比如下:
| 容器类型 | 有序性 | 关键字(key)是否唯一 | 底层实现 | 核心效率(插入/查找/删除) | 核心优势 |
|---|---|---|---|---|---|
| map | ✅ 是(默认升序) | ✅ 唯一 | 红黑树(平衡二叉搜索树) | O(log n)(稳定) | 有序映射,支持按key排序、范围查找 |
| unordered_map | ❌ 否 | ✅ 唯一 | 哈希表 | O(1)(平均),最坏O(n) | 查找速度极快,适合高频映射查询 |
补充:与map对应的“允许重复key”的容器为 multimap(有序)和 unordered_multimap(无序),核心区别是key可重复,value可不同,用法与map基本一致,仅插入和查找时需注意key的重复性。
二、map与set的核心区别
很多初学者会混淆map和set,二者同属关联式容器,但核心用途不同,具体区别如下:
- 存储单元不同:set仅存储“值”(value),map存储“键值对(key-value)”;
- 核心作用不同:set侧重“去重、排序、查找”,map侧重“关键字映射”(通过key找value);
- 关键字不同:set的关键字就是自身的值,map的关键字是独立的key,与value分离。
三、逐一详解:map系列容器用法
1. map:有序、key唯一的键值对映射
map是最常用的map系列容器,key唯一,插入后会自动按key升序排列,支持通过key快速查找、修改对应的value。
基础用法(完整代码)
cpp
#include <iostream>
#include <map> // map的头文件
using namespace std;
int main() {
// 1. 定义:key为int类型,value为string类型(默认key升序)
map<int, string> mp;
// 2. 插入元素(三种方式,推荐前两种)
mp.insert(pair<int, string>(1, "apple")); // 方式1:pair插入
mp.emplace(2, "banana"); // 方式2:emplace插入(更高效)
mp[3] = "orange"; // 方式3:[]赋值插入(不存在则创建,存在则修改)
// 注意:key唯一,重复插入会失败
mp.insert(pair<int, string>(1, "pear")); // 重复key,插入无效
// 3. 遍历(自动按key升序)
cout << "map遍历(按key升序):" << endl;
for (auto it = mp.begin(); it != mp.end(); it++) {
// it->first 是key,it->second 是value
cout << "key:" << it->first << ",value:" << it->second << endl;
}
// 输出:
// key:1,value:apple
// key:2,value:banana
// key:3,value:orange
// 4. 查找元素(通过key查找)
auto find_it = mp.find(2); // 查找key=2的元素,返回迭代器
if (find_it != mp.end()) {
cout << "\n找到key=2,对应的value:" << find_it->second << endl;
} else {
cout << "\n未找到key=2" << endl;
}
// 5. 修改value(通过key修改)
mp[2] = "grape"; // 直接通过[]修改key对应的value
cout << "\n修改后key=2的value:" << mp[2] << endl; // 输出:grape
// 6. 删除元素(三种方式)
mp.erase(3); // 方式1:通过key删除
// mp.erase(find_it); // 方式2:通过迭代器删除(删除key=2)
// mp.erase(mp.begin(), mp.end()); // 方式3:删除指定范围元素
// 7. 其他常用操作
cout << "\nmap中元素个数:" << mp.size() << endl; // 输出:2(删除了key=3)
if (mp.empty()) {
cout << "map为空" << endl;
} else {
cout << "map非空" << endl;
}
mp.clear(); // 清空map
return 0;
}补充:key 降序排列与 set 类似,map 也支持自定义排序,实现 key 降序:
cpp
// 定义降序排序规则
struct cmp {
bool operator()(const int& a, const int& b) const {
return a > b; // key降序
}
};
map<int, string, cmp> mp; // 降序map
mp.emplace(1, "apple");
mp.emplace(2, "banana");
// 遍历输出:key:2,value:banana;key:1,value:apple2. unordered_map:无序、key 唯一的键值对映射
unordered_map 与 map 的核心区别是「无序」,底层基于哈希表实现,查找、插入、删除的平均效率比 map 高,但不支持排序,key 同样唯一。
基础用法(核心代码)
cpp
#include <iostream>
#include <unordered_map> // unordered_map的头文件
using namespace std;
int main() {
// 1. 定义:key为string类型,value为int类型(无序)
unordered_map<string, int> umap;
// 2. 插入元素(与map用法一致)
umap.emplace("apple", 10);
umap.emplace("banana", 20);
umap["orange"] = 15;
umap.emplace("apple", 12); // 重复key,插入无效
// 3. 遍历(无序,每次运行顺序可能不同)
cout << "unordered_map遍历(无序):" << endl;
for (auto& pair : umap) {
cout << "key:" << pair.first << ",value:" << pair.second << endl;
}
// 示例输出(顺序不固定):
// key:banana,value:20
// key:apple,value:10
// key:orange,value:15
// 4. 查找、修改、删除(与map用法一致)
auto find_it = umap.find("orange");
if (find_it != umap.end()) {
cout << "\n找到key=orange,value:" << find_it->second << endl;
}
umap["orange"] = 18; // 修改value
umap.erase("banana"); // 删除key=banana
// 5. 其他常用操作
cout << "\nunordered_map元素个数:" << umap.size() << endl; // 输出:2
umap.clear();
return 0;
}3. multimap:有序、key 可重复的键值对映射
multimap 与 map 的核心区别是「key 可重复」,底层同样是红黑树,支持按 key 升序排列,适合需要多个相同 key 对应不同 value 的场景(如:一个学生对应多门课程成绩)。
基础用法(核心代码)
cpp
#include <iostream>
#include <map>
using namespace std;
int main() {
multimap<string, int> mmp; // key可重复,有序
// 插入相同key的不同value
mmp.emplace("张三", 90);
mmp.emplace("张三", 85);
mmp.emplace("李四", 95);
// 遍历(按key升序,相同key的value按插入顺序排列)
cout << "multimap遍历:" << endl;
for (auto& pair : mmp) {
cout << "key:" << pair.first << ",value:" << pair.second << endl;
}
// 输出:
// key:张三,value:90
// key:张三,value:85
// key:李四,value:95
// 统计相同key的个数
cout << "\n张三的成绩个数:" << mmp.count("张三") << endl; // 输出:2
// 查找所有key=张三的元素
auto range = mmp.equal_range("张三");
cout << "\n张三的所有成绩:";
for (auto it = range.first; it != range.second; it++) {
cout << it->second << " ";
}
cout << endl; // 输出:90 85
return 0;
}4. unordered_multimap:无序、key 可重复的键值对映射
unordered_multimap 与 unordered_map 的核心区别是「key 可重复」,底层基于哈希表实现,无序,适合需要快速统计相同 key 对应多个 value 的场景,用法与 multimap 类似,仅无排序功能。
四、常用操作汇总(map 系列通用)
| 操作 | 语法 | 说明 |
|---|---|---|
| 插入 | insert(pair) / emplace(key, value) / [key] = value | emplace 效率最高,[] 可用于插入和修改 |
| 查找 | find(key) | 返回指向该 key 的迭代器,找不到返回 end () |
| 统计个数 | count(key) | 返回该 key 的个数(map/unordered_map 只能是 0 或 1) |
| 修改 value | map[key] = new_value | 仅 map/unordered_map 支持,multimap 需通过迭代器修改 |
| 删除 | erase (key) /erase (迭代器) /erase (范围) | 按 key 删除时,multimap 会删除所有该 key 的元素 |
| 清空 | clear() | 清空所有键值对 |
| 判空 | empty() | 为空返回 true,否则返回 false |
| 获取大小 | size() | 返回键值对的个数 |
五、适用场景总结(一句话选型)
有序映射、key 唯一 → 用 map(如:用户 ID 对应用户名,需要按 ID 排序); 快速映射、key 唯一、不在乎顺序 → 用 unordered_map(效率最优,如:缓存映射、快速查询); 有序映射、key 可重复 → 用 multimap(如:一个 key 对应多个 value,需要排序); 快速映射、key 可重复、不在乎顺序 → 用 unordered_multimap(如:统计相同 key 的多个 value)。
六、注意事项
map 系列容器的 key 是不可修改的(底层红黑树 / 哈希表依赖 key 排序 / 哈希),若需修改 key,需先删除旧 key,再插入新 key; unordered_map 的 key 需要支持哈希函数,自定义类型作为 key 时,需重写哈希函数和 == 运算符; multimap 不支持 [] 操作符(因为 key 可重复,无法确定对应哪个 value),修改 value 需通过迭代器; 头文件区分:map、multimap 包含 <map>;unordered_map、unordered_multimap 包含 <unordered_map>。
