【std::map】与std::unordered_map操作差异

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


你想了解 unordered_mapmap 在遍历、插入、查找、删除这些核心操作上的具体使用差异,同时希望我详细介绍 unordered_map 仅支持前向迭代器的具体用法——这是非常关键的实操问题,二者虽然基础 API 相似,但细节行为和迭代器限制直接影响代码的正确性和性能。

一、核心操作的使用差异(插入/查找/删除)

先明确:unordered_mapmap基础 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::findO(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

总结

  1. 基础操作语法unordered_mapmap 的插入([]/insert/emplace)、查找(find/count)、删除(erase)语法几乎一致,核心差异在行为(有序性、性能、迭代器稳定性);
  2. 迭代器限制unordered_map 仅支持前向迭代器,只能用 ++ 向前遍历,无法反向遍历或用 -- 向后移动;map 是双向迭代器,支持 ++/-- 和反向遍历;
  3. 功能补充map 支持 lower_bound/upper_bound 范围查找,unordered_map 无此功能,仅适合单元素查找。

实际使用时,若不需要有序性且追求查找性能,优先用 unordered_map;若需要有序遍历或范围查找,选择 map 即可。


vs测试发现
unordered_map 可以使用 - - 移动
后面继续追问,说明原因

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值