首页 / 第十一章 · STL 标准模板库 / 11.9 unordered_map

11.9 unordered_map 无序映射

不需要顺序、只追求最快查找速度时的选择——底层用哈希表实现,平均查找速度 O(1),比 map 的 O(log n) 更快。

本页目录

如果你不需要元素保持有序,只追求最快的查找速度,可以用 unordered_map。它底层用哈希表实现,平均查找速度是 O(1),比 map 的 O(log n) 更快。代价是元素没有顺序,遍历时是乱的。使用前需引入 <unordered_map> 头文件。

哈希表的原理:用哈希函数把 key 算成一个桶编号,直接跳过去
"Bob" hash("Bob") = 2 [0] 空 [1] 空 [2] Bob:92 [3] 空 [4] Eve:95 [5] 空 查找 / 插入时,先算哈希值定位到桶,再在桶里比对 —— 平均 O(1),但顺序和插入顺序、键的大小都无关
核心思路:用一个哈希函数把任意类型的键算成一个数字(桶编号),直接跳到对应的桶里去找,不需要像 map 的红黑树那样一层层比较。这就是为什么 unordered_map 平均是 O(1),但代价是元素在内存里的排列和"键的大小"毫无关系——遍历顺序看起来是乱的。
11.9.1 定义与初始化
C++ · unordered_map 的定义方式
1#include <iostream>
2#include <unordered_map> // 必须包含这个头文件
3using namespace std;
4
5int main()
6{
7 unordered_map<string, int> um; // 用法和 map 完全一样
8 um["Alice"] = 85;
9 um["Bob"] = 92;
10 um.insert({"Carol", 78});
11 return 0;
12}
💡
好消息:unordered_map 的接口和 map 几乎完全一样——[]at()insert()erase()find()count() 全都能直接照搬,11.8 节学的所有陷阱([] 自动插入、insert 不覆盖)在这里同样适用。唯一的本质区别是:没有顺序
11.9.2 常用操作
C++ · 用法和 map 一致,但遍历顺序是乱的
1unordered_map<string, int> um;
2um["Alice"] = 85; // 用法和 map 完全一样
3um["Bob"] = 92;
4um.insert({"Carol", 78});
5
6// 查找也是 O(1),比 map 更快
7if (um.count("Alice"))
8{
9 cout << um["Alice"] << endl;
10}
11
12// 遍历——注意顺序是乱的!
13for (auto& p : um)
14{
15 cout << p.first << ": " << p.second << endl; // 输出顺序不确定
16}
⚠️
不要依赖 unordered_map 的遍历顺序!不同编译器、不同版本的 STL 实现,甚至同一个程序运行两次,unordered_map 的遍历顺序都可能不一样。如果题目要求按某种顺序输出,千万不要用 unordered_map,要么用 map,要么把键取出来单独排序。
对比项mapunordered_map
底层结构红黑树哈希表
查找/插入/删除O(log n)平均 O(1),最坏 O(n)
遍历顺序按键自动升序无序,不可预测
键的要求需支持 < 比较需支持哈希和 ==
典型场景需要顺序、范围查询只要快速查找,不关心顺序
11.9.3 完整使用示例
C++ · unordered_map 综合示例
1#include <iostream>
2#include <unordered_map>
3#include <vector>
4using namespace std;
5
6int main()
7{
8 unordered_map<string, int> wordCount;
9
10 // 统计单词出现次数(不需要顺序,最适合 unordered_map)
11 vector<string> words = {"apple", "banana", "apple", "cherry", "apple"};
12 for (auto& w : words) {
13 wordCount[w]++; // 不存在则自动插入 0,再 +1
14 }
15
16 for (auto& p : wordCount) {
17 cout << p.first << ": " << p.second << endl;
18 }
19 // 输出顺序不确定,但每个单词的计数一定是对的:
20 // apple: 3, banana: 1, cherry: 1(顺序可能不同)
21
22 return 0;
23}
📋 unordered_map 常用操作速查表

把本节出现过的方法按用途归类汇总,写代码时可以直接当参考卡用——和 map 几乎一模一样,主要区别在备注列。

方法分类作用
um[key] = val插入/修改赋值,键存在则覆盖,不存在则插入
um.insert({key, val})插入插入,键已存在则不覆盖
um.erase(key)删除删除指定键的元素
um[key]查找键不存在时自动插入默认值,要小心
um.at(key)查找键不存在时抛出异常,更安全
um.find(key)查找返回迭代器,没找到返回 end(),平均 O(1)
um.count(key)查找判断键是否存在,返回 0 或 1
um.size() / um.empty()容量元素个数 / 判断是否为空
um.clear()容量清空所有元素
um.begin() / um.end()遍历迭代器范围,顺序不保证,不要依赖
🎯
什么时候用 unordered_map?统计词频、去重计数、缓存(cache)、任何"只关心能不能查到、不关心顺序"的场景。如果数据量很大且查找是性能瓶颈,unordered_map 通常比 map 快不少。但如果键的哈希冲突很多,最坏情况会退化到 O(n),竞赛中要留意这一点。