3 条题解
-
1
C++ STL unordered_map 方法和用法指南
概述
unordered_map是 C++ STL 中的哈希表实现,提供平均 O(1) 的查找、插入和删除性能。
主要方法
1. 构造和析构
#include <unordered_map> unordered_map<int, string> map1; // 默认构造 unordered_map<int, string> map2(map1); // 拷贝构造 unordered_map<int, string> map3 = {{1, "a"}, {2, "b"}}; // 初始化列表构造2. 元素访问
unordered_map<int, string> map; map[1] = "apple"; map[2] = "banana"; // at() - 访问,键不存在时抛出 out_of_range 异常 string val = map.at(1); // "apple" // string val2 = map.at(3); // 抛出异常 // operator[] - 访问或插入 string val = map[1]; // "apple" map[3] = "cherry"; // 如果键不存在,则插入默认值后赋值3. 查找元素
unordered_map<int, string> map = {{1, "a"}, {2, "b"}}; // find() - 返回迭代器 auto it = map.find(1); if (it != map.end()) { cout << it->first << ": " << it->second << endl; // 1: a } else { cout << "Not found" << endl; } // count() - 返回 0 或 1(unordered_map 中无重复键) if (map.count(2) > 0) { cout << "Key 2 exists" << endl; } // contains() - C++20 标准 if (map.contains(1)) { cout << "Key 1 exists" << endl; }4. 插入元素
unordered_map<int, string> map; // insert() - 插入单个键值对 map.insert({1, "apple"}); map.insert(make_pair(2, "banana")); // insert() - 插入范围 unordered_map<int, string> map2 = {{3, "cherry"}, {4, "date"}}; map.insert(map2.begin(), map2.end()); // emplace() - 就地构造插入,通常更高效 map.emplace(5, "elderberry"); // 检查插入是否成功 auto result = map.insert({1, "new_apple"}); if (!result.second) { cout << "Key 1 already exists, insertion failed" << endl; }operator[]vsinsert()的区别特性 operator[]insert()键不存在时 创建新项,值初始化为默认值 返回 pair,可判断是否插入成功 键已存在时 覆盖旧值 不覆盖,保持原值 返回值 引用(对值的引用) pair<iterator, bool> 能否判断是否成功 否 是 效率 快(直接访问或插入) 快(但需要检查返回值) 适用场景 赋值、更新 仅插入新元素、批量插入、判断插入结果 实际代码对比
unordered_map<int, string> map; // 场景 1:想插入,但不想覆盖已有的值 // 用 operator[] 实现:无法判断是否覆盖 map[10] = "first"; map[10] = "second"; // 覆盖了原值,但你无法察觉 // 用 insert() 实现:可以明确知道 auto result = map.insert({10, "first"}); if (result.second) { cout << "插入成功" << endl; } else { cout << "键已存在,插入失败,原值为: " << result.first->second << endl; } // 场景 2:想批量插入 vector<pair<int, string>> data = {{1, "a"}, {2, "b"}, {3, "c"}}; // operator[] 无法直接批量操作 // insert() 可以 : map.insert(data.begin(), data.end()); // 场景 3:只想访问,不想创建新元素 int key = 999; // 用 operator[] 会创建新元素,改变 map 的大小 // map[999]; // 这会在 map 中创建 999 这个键 // 用 find() 或 count() : if (map.count(999)) { cout << map[999] << endl; } else { cout << "键不存在" << endl; }总结
operator[]: 适合做值的赋值和更新,简洁直观insert()/emplace(): 适合仅插入新元素,且需要判断是否插入成功的场景find()/count()/at(): 适合仅查询,不想修改 map 的场景
5. 删除元素
unordered_map<int, string> map = {{1, "a"}, {2, "b"}, {3, "c"}}; // erase() - 按键删除 map.erase(1); // erase() - 按迭代器删除 auto it = map.find(2); if (it != map.end()) { map.erase(it); } // erase() - 删除范围 auto it1 = map.find(1); auto it2 = map.find(3); map.erase(it1, it2); // clear() - 清空所有元素 map.clear();6. 容量和大小
unordered_map<int, string> map = {{1, "a"}, {2, "b"}, {3, "c"}}; // size() - 返回元素个数 cout << map.size() << endl; // 3 // empty() - 检查是否为空 if (map.empty()) { cout << "Map is empty" << endl; } else { cout << "Map is not empty" << endl; } // max_size() - 返回理论最大元素个数 cout << map.max_size() << endl;7. 迭代器
unordered_map<int, string> map = {{1, "a"}, {2, "b"}, {3, "c"}}; // begin() 和 end() for (auto it = map.begin(); it != map.end(); ++it) { cout << it->first << ": " << it->second << endl; } // 范围 for 循环(推荐)- C++17 结构化绑定 for (auto& [key, value] : map) { cout << key << ": " << value << endl; } // C++14 及以下兼容写法 for (auto& p : map) { cout << p.first << ": " << p.second << endl; } // cbegin() 和 cend() - 常量迭代器 for (auto it = map.cbegin(); it != map.cend(); ++it) { cout << it->first << ": " << it->second << endl; }C++14 兼容性说明
CSP/NOI比赛限制只能用C++14标准
写法 C++14 C++17+ 说明 for (auto it = map.begin(); ...)✅ ✅ 传统迭代器遍历,所有版本都支持 for (auto& p : map)范围 for 循环,C++11 起支持 for (auto& [key, value] : map)❌ 结构化绑定,需要 C++17 不同 C++ 版本的写法对比
unordered_map<int, string> map = {{1, "a"}, {2, "b"}}; // C++14 及以下 - 推荐写法 for (auto& p : map) { int key = p.first; string value = p.second; cout << key << ": " << value << endl; } // C++14 - 另一种写法(不推荐,冗长) for (const auto& pair : map) { cout << pair.first << ": " << pair.second << endl; } // C++17+ - 最简洁写法(使用结构化绑定) for (auto& [key, value] : map) { cout << key << ": " << value << endl; } // C++11 - 传统迭代器写法 for (auto it = map.begin(); it != map.end(); ++it) { cout << it->first << ": " << it->second << endl; }8. 桶相关操作
unordered_map<int, string> map = {{1, "a"}, {2, "b"}}; // bucket_count() - 返回桶的数量 cout << "Bucket count: " << map.bucket_count() << endl; // load_factor() - 返回负载因子 (元素数 / 桶数) cout << "Load factor: " << map.load_factor() << endl; // max_load_factor() - 获取或设置最大负载因子 cout << "Max load factor: " << map.max_load_factor() << endl; map.max_load_factor(0.75); // rehash() - 重新哈希,指定桶的数量 map.rehash(100);
完整示例
#include <iostream> #include <unordered_map> using namespace std; int main() { unordered_map<int, string> students; // 添加元素 students[1001] = "Alice"; students[1002] = "Bob"; students.emplace(1003, "Charlie"); // 遍历 cout << "All students:" << endl; for (auto& [id, name] : students) { cout << "ID: " << id << ", Name: " << name << endl; } // 查找 if (students.count(1002)) { cout << "Student 1002: " << students[1002] << endl; } // 更新 students[1001] = "Alice (updated)"; // 删除 students.erase(1003); cout << "Remaining students: " << students.size() << endl; return 0; }输出:
All students: ID: 1003, Name: Charlie ID: 1001, Name: Alice ID: 1002, Name: Bob Student 1002: Bob Remaining students: 2
常见用途
用途 代码 频率统计 unordered_map<char, int> freq; freq[ch]++;键值映射 unordered_map<string, int> mapping; mapping["age"] = 25;缓存 if (cache.count(key)) return cache[key];去重 unordered_map<int, bool> seen; if (!seen[x]) seen[x] = true;频率:数学统计术语,指某个值出现的次数
信息
- ID
- 19385
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 10
- 标签
- (无)
- 递交数
- 5
- 已通过
- 4
- 上传者