提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
你想了解 unordered_map 和 map 在遍历、插入、查找、删除这些核心操作上的具体使用差异,同时希望我详细介绍 unordered_map 仅支持前向迭代器的具体用法——这是非常关键的实操问题,二者虽然基础 API 相似,但细节行为和迭代器限制直接影响代码的正确性和性能。
一、核心操作的使用差异(插入/查找/删除)
先明确:unordered_map 和 map 的基础 API 语法几乎一致,但行为(如有序性、迭代器稳定性)和功能支持(如范围查找)有显著差异。以下结合代码示例对比说明:
1. 插入操作
相同点
都支持 3 种核心插入方式:[] 运算符、insert() 函数、emplace() 函数(C++11+,更高效)。
不同点
map插入时会自动按 key 升序排序(可自定义排序规则);unordered_map插入时按 key 的哈希值分配存储位置,无序;unordered_map插入可能触发rehash(哈希表扩容),导致所有迭代器失效;map插入不会导致任何迭代器失效(仅红黑树指针调整,节点结构不变)。
#include <iostream>
#include <map>
#include <unordered_map>
using namespace std;
int main() {
// map 插入:自动按 key 升序
map<int, string> mp;
mp[3] = "three"; // 方式1:[]运算符(不存在则插入,存在则修改)
mp.insert({1, "one"}); // 方式2:insert
mp.emplace(2, "two"); // 方式3:emplace(直接构造,更高效)
cout << "map 遍历(有序):";
for (auto& p : mp) cout << p.first << ":" << p.second << " "; // 输出:1:one 2:two 3:three
// unordered_map 插入:无序
unordered_map<int, string> ump;
ump[3] = "three";
ump.insert({1, "one"});
ump.emplace(2, "two");
cout << "\nunordered_map 遍历(无序):";
for (auto& p : ump) cout << p.first << ":" << p.second << " "; // 输出顺序不确定(如 3:three 1:one 2:two)
return 0;
}
2. 查找操作
相同点
都支持 find(key)(返回迭代器,找不到则返回 end())、count(key)(返回 0/1,判断 key 是否存在)。
不同点
map额外支持lower_bound(key)/upper_bound(key)(范围查找,利用有序性),unordered_map无此接口;- 时间复杂度:
map::find是O(log n),unordered_map::find平均O(1)、最坏O(n)。
// 查找示例
map<int, string> mp = {{1,"one"}, {2,"two"}, {3,"three"}};
unordered_map<int, string> ump = {{1,"one"}, {2,"two"}, {3,"three"}};
// 通用查找方式
auto it1 = mp.find(2);
if (it1 != mp.end()) cout << "\nmap 找到:" << it1->second; // 输出 two
auto it2 = ump.find(2);
if (it2 != ump.end()) cout << "\nunordered_map 找到:" << it2->second; // 输出 two
// map 独有:范围查找
auto it_low = mp.lower_bound(2); // 第一个 >=2 的元素(key=2)
auto it_up = mp.upper_bound(2); // 第一个 >2 的元素(key=3)
cout << "\nmap 范围查找 [2,3):" << it_low->second << " " << it_up->second; // 输出 two three
// unordered_map 无 lower_bound/upper_bound,编译报错
// auto it_ump = ump.lower_bound(2); // 错误!
3. 删除操作
相同点
都支持 3 种删除方式:
erase(迭代器):删除迭代器指向的元素;erase(key):删除指定 key 的元素(返回删除的个数,0 或 1);erase(迭代器起始, 迭代器结束):删除范围元素。
不同点
迭代器稳定性:
map:删除操作后,除被删除元素的迭代器外,其他所有迭代器仍有效;unordered_map:删除操作不会触发rehash,因此仅被删除元素的迭代器失效,其他迭代器/引用均有效。
// 删除示例
map<int, string> mp = {{1,"one"}, {2,"two"}, {3,"three"}};
unordered_map<int, string> ump = {{1,"one"}, {2,"two"}, {3,"three"}};
// 方式1:按 key 删除
mp.erase(2); // map 删除 key=2
int del_cnt = ump.erase(2); // unordered_map 删除 key=2,返回 1
cout << "\nunordered_map 删除个数:" << del_cnt; // 输出 1
// 方式2:按迭代器删除
auto it_mp = mp.find(1);
if (it_mp != mp.end()) mp.erase(it_mp); // map 删除 key=1
// 方式3:范围删除(仅 map 有实际意义,因为有序)
mp.erase(mp.begin(), mp.find(3)); // 删除 [begin, 3) 的元素(无剩余)
二、遍历与迭代器的核心差异(重点讲前向迭代器)
迭代器类型是二者最核心的使用差异,直接决定遍历方式:
| 迭代器特性 | map(双向迭代器) | unordered_map(前向迭代器) |
|---|---|---|
| 移动方向 | 支持 ++(向前)、--(向后) | 仅支持 ++(向前),-- 编译报错 |
| 反向遍历 | 支持 rbegin()/rend()(逆序遍历) | 无 rbegin()/rend(),无法反向遍历 |
| 随机访问 | 均不支持(不能用 it+1/it[0]) | 均不支持 |
1. map(双向迭代器)的遍历示例
支持正向、反向遍历,可前后移动迭代器:
map<int, string> mp = {{1,"one"}, {2,"two"}, {3,"three"}};
// 正向遍历(++)
cout << "\nmap 正向遍历:";
for (auto it = mp.begin(); it != mp.end(); ++it) {
cout << it->first << ":" << it->second << " "; // 1:one 2:two 3:three
}
// 反向遍历(rbegin/rend)
cout << "\nmap 反向遍历:";
for (auto it = mp.rbegin(); it != mp.rend(); ++it) {
cout << it->first << ":" << it->second << " "; // 3:three 2:two 1:one
}
// 迭代器向后移动(--)
auto it = mp.find(3);
--it; // 合法,指向 key=2
cout << "\nmap 迭代器--:" << it->second; // 输出 two
2. unordered_map(前向迭代器)的遍历示例
仅支持正向遍历,-- 或反向遍历会编译错误:
unordered_map<int, string> ump = {{1,"one"}, {2,"two"}, {3,"three"}};
// 正向遍历(仅支持 ++)
cout << "\nunordered_map 正向遍历:";
for (auto it = ump.begin(); it != ump.end(); ++it) {
cout << it->first << ":" << it->second << " "; // 无序,如 3:three 1:one 2:two
}
// 错误示例1:-- 迭代器(编译报错)
auto it = ump.find(3);
// --it; // 错误!前向迭代器不支持 -- 操作
// 错误示例2:反向遍历(编译报错)
// for (auto it = ump.rbegin(); it != ump.rend(); ++it) {} // 错误!unordered_map 无 rbegin/rend
总结
- 基础操作语法:
unordered_map和map的插入([]/insert/emplace)、查找(find/count)、删除(erase)语法几乎一致,核心差异在行为(有序性、性能、迭代器稳定性); - 迭代器限制:
unordered_map仅支持前向迭代器,只能用++向前遍历,无法反向遍历或用--向后移动;map是双向迭代器,支持++/--和反向遍历; - 功能补充:
map支持lower_bound/upper_bound范围查找,unordered_map无此功能,仅适合单元素查找。
实际使用时,若不需要有序性且追求查找性能,优先用 unordered_map;若需要有序遍历或范围查找,选择 map 即可。
注
vs测试发现
unordered_map 可以使用 - - 移动
后面继续追问,说明原因

988

被折叠的 条评论
为什么被折叠?



