往期回顾:
C++ 入门18:STL 容器之栈(stack)与队列(queue)-优快云博客
C++ 入门第 21 天:STL 容器之无序映射与无序多重映射
一、前言
在前一节中,我们学习了无序集合(unordered_set
)及其变种。在实际开发中,除了存储单个元素外,我们常常需要存储键值对(key-value)数据。例如,通过一个键快速找到对应的值。在 C++ 中,unordered_map
和 unordered_multimap
便是专门用于处理无序键值对的容器。
这两个容器基于哈希表实现,能够以平均 O(1)O(1)O(1) 的时间完成插入、删除和查找操作。
1. 无序映射(unordered_map)
unordered_map
是一个 无序关联容器,用于存储唯一键值对(key-value)。它的特点包括:
- 底层实现:基于哈希表,效率高。
- 键的唯一性:键(key)必须唯一。
- 无序存储:键值对的存储顺序与插入顺序无关。
1.1 常用操作
以下是 unordered_map
的常用操作:
成员函数 | 功能说明 |
insert(pair<key, value>) | 插入键值对 |
erase(key) | 删除指定键对应的键值对 |
find(key) | 查找键,返回对应迭代器 |
operator[] | 通过键访问值(若不存在会自动插入) |
size() | 获取键值对的数量 |
empty() | 检查容器是否为空 |
示例代码:基本操作
#include <iostream>
#include <unordered_map>
using namespace std;
int main() {
// 定义一个无序映射
unordered_map<string, int> umap;
// 插入键值对
umap.insert({"Alice", 25});
umap.insert({"Bob", 30});
umap["Charlie"] = 20; // 使用[]操作符插入
// 遍历容器
cout << "Contents of unordered_map:" << endl;
for (const auto& pair : umap) {
cout << pair.first << ": " << pair.second << endl;
}
// 查找键
if (umap.find("Alice") != umap.end()) {
cout << "Alice's age: " << umap["Alice"] << endl;
}
// 删除键
umap.erase("Bob");
cout << "After removing Bob:" << endl;
for (const auto& pair : umap) {
cout << pair.first << ": " << pair.second << endl;
}
return 0;
}
输出结果(顺序可能不同):
Contents of unordered_map:
Charlie: 20
Alice: 25
Bob: 30
Alice's age: 25
After removing Bob:
Charlie: 20
Alice: 25
1.2 注意事项
- 自动插入行为:如果通过
[]
访问不存在的键,会自动插入该键,值初始化为默认值(如int
为 0)。 - 哈希冲突处理:
unordered_map
使用开放地址法或链地址法解决冲突。 - 重新哈希(rehash):当装载因子过高时,会重新分配存储桶,导致性能下降。
2. 无序多重映射(unordered_multimap)
unordered_multimap
与 unordered_map
类似,但允许键重复。
2.1 常用操作
成员函数 | 功能说明 |
insert(pair<key, value>) | 插入键值对 |
equal_range(key) | 返回与某键相关的所有键值对的范围 |
count(key) | 返回某键出现的次数 |
示例代码:无序多重映射
#include <iostream>
#include <unordered_map>
using namespace std;
int main() {
// 定义一个无序多重映射
unordered_multimap<string, int> ummap;
// 插入键值对
ummap.insert({"Alice", 25});
ummap.insert({"Bob", 30});
ummap.insert({"Alice", 35}); // 允许重复键
// 遍历容器
cout << "Contents of unordered_multimap:" << endl;
for (const auto& pair : ummap) {
cout << pair.first << ": " << pair.second << endl;
}
// 查找某键的所有值
auto range = ummap.equal_range("Alice");
cout << "Values associated with Alice:" << endl;
for (auto it = range.first; it != range.second; ++it) {
cout << it->second << " ";
}
cout << endl;
return 0;
}
输出结果(顺序可能不同):
Contents of unordered_multimap:
Alice: 25
Bob: 30
Alice: 35
Values associated with Alice:
25 35
3. unordered_map
和 unordered_multimap
的性能分析
优点
- 高效操作:基于哈希表,插入、删除和查找操作的平均时间复杂度为 O(1)O(1)O(1)。
- 灵活性强:支持键值对存储,方便快速检索和更新数据。
缺点
- 无序存储:键值对的顺序与插入顺序无关,适合只关心内容的场景。
- 哈希冲突:在哈希函数不理想或装载因子过高时,性能可能下降。
- 占用内存多:哈希表存储需要额外的内存开销。
4. 实际应用场景
- 快速检索:通过键快速找到对应值,例如字典查询。
- 频率统计:统计某些键的出现次数(可用
unordered_multimap
)。 - 缓存机制:用作缓存容器,通过键值快速检索数据。
示例:统计单词出现次数
题目描述
给定一段文本,统计每个单词出现的次数。
示例代码
#include <iostream>
#include <unordered_map>
#include <sstream>
#include <string>
using namespace std;
int main() {
string text = "hello world hello C++ world";
unordered_map<string, int> wordCount;
// 将字符串分割为单词
stringstream ss(text);
string word;
while (ss >> word) {
wordCount[word]++;
}
// 输出每个单词的出现次数
cout << "Word frequencies:" << endl;
for (const auto& pair : wordCount) {
cout << pair.first << ": " << pair.second << endl;
}
return 0;
}
输出结果:
Word frequencies:
hello: 2
world: 2
C++: 1
5. unordered_map
和 map
的对比
特性 | unordered_map | map |
底层结构 | 哈希表 | 红黑树 |
是否有序 | 无序 | 有序 |
查找时间复杂度 | O(1)O(1)O(1)(平均情况) | O(logn)O(\log n)O(logn) |
插入、删除时间复杂度 | O(1)O(1)O(1)(平均情况) | O(logn)O(\log n)O(logn) |
结语
以上就是 C++ 标准模板库中的无序映射与无序多重映射的基础知识点了。这两种容器非常适合需要快速检索键值对数据的场景。理解它们的特性和使用方法,可以显著提升我们的代码效率。
都看到这里了,点个赞再走呗朋友~
加油吧,预祝大家变得更强!