C++STL剖析(九)—— unordered_map和unordered_multimap的概念和使用
文章目录
- 1. unordered_map的介绍和使用
- 🍑 unordered_map的构造
- 🍑 unordered_map的使用
- 🍅 insert
- 🍅 operator[ ]
- 🍅 find
- 🍅 erase
- 🍅 size
- 🍅 empty
- 🍅 clear
- 🍅 swap
- 🍅 count
- 2. unordered_multimap的介绍和使用
- 🍑 unordered_multimap的使用
- 🍅 find
- 🍅 count
1. unordered_map的介绍和使用
unordered_map 的介绍:
- unordered_map 是存储
<key, value>键值对的关联式容器,其允许通过keys快速的索引到与其对应的 value。 - 在 unordered_map 中,键值通常用于惟一地标识元素,而映射值是一个对象,其内容与此键关联。键和映射值的类型可能不同。
- 在内部,unordered_map 没有对
<kye, value>按照任何特定的顺序排序,为了能在常数范围内找到 key 所对应的 value,unordered_map 将相同哈希值的键值对放在相同的桶中。 - unordered_map 容器通过 key 访问单个元素要比 map 快,但它通常在遍历元素子集的范围迭代方面效率较低。
- unordered_map 实现了直接访问操作符(
operator[]),它允许使用 key 作为参数直接访问 value。 - 它的迭代器至少是前向迭代器。
🍑 unordered_map的构造
构造一个 unordered_map 容器对象,根据使用的构造函数版本初始化其内容,我们主要掌握 3 种方式即可:

(1)构造一个某个类型的空容器
unordered_map<string, int> um1; // 构造一个key为string类型,value为int类型的空容器
(2)拷贝构造某类型容器
unordered_map<string, int> um1({ {"apple", 1}, {"lemon", 2}});
unordered_map<string, int> um2(um1); // 拷贝构造同类型容器um1的复制品
(3)使用迭代器区间进行初始化构造
构造一个 unordered_map 对象,其中包含范围 [first,last) 中每个元素的副本。
unordered_map<string, int> um1({ {"apple", 1}, {"lemon", 2}});
unordered_map<string, int> um3(um1.begin(), um1.end()); // 使用迭代器拷贝构造um1容器某段区间的复制品
🍑 unordered_map的使用
unordered_map 的成员函数主要分为:迭代器,容量操作,修改操作。

我这里只列举几个常用的,其它的可以看 文档 学习。
🍅 insert
在 unordered_map 中插入新元素。
只有当每个元素的键不等同于容器中已经存在的任何其他元素的键时,才会插入它,也就是说 unordered_map 中的键是唯一的。

(1)构造匿名对象插入
void test_unordered()
{// 构造对象unordered_map<string, double> um({ {"apple", 1.0}, {"lemon", 2.0} });// 构造匿名对象插入新元素um.insert(pair<string, double>("milk", 2.0));um.insert(pair<string, double>("eggs", 6.5));um.insert(pair<string, double>("sugar", 0.8));// 遍历for (auto e : um){cout << e.first << ": " << e.second << endl;}
}
运行结果

(2)调用 make_pair 函数模板插入
void test_unordered()
{// 构造对象unordered_map<string, double> um({ {"apple", 1.0}, {"lemon", 2.0} });// 调用make_pair函数模板插入新元素um.insert(make_pair("milk", 2.0));um.insert(make_pair("eggs", 6.5));um.insert(make_pair("sugar", 0.8));// 遍历for (auto e : um){cout << e.first << ": " << e.second << endl;}
}
运行结果

(3)初始化列表插入
void test_unordered()
{// 构造对象unordered_map<string, double> um({ {"apple", 1.0}, {"lemon", 2.0} });// 初始化列表插入新元素um.insert({ "sugar", 0.8 });um.insert({ "eggs", 6.5 });um.insert({ "salt", 0.1 } );// 遍历for (auto e : um){cout << e.first << ": " << e.second << endl;}
}
运行结果

🍅 operator[ ]
如果 k 与容器中元素的键匹配,则函数返回对其映射值的引用。
如果 k 与容器中任何元素的键不匹配,该函数将插入一个具有该键的新元素,并返回对其映射值的引用。
注意:这总是将容器大小增加 1,即使没有为元素分配映射值(使用默认构造函数构造元素)。

(1)利用 [] 运算符重载函数进行插入
void test_unordered()
{// 构造对象unordered_map<string, double> um;// 利用[]运算符重载函数进行插入um["apple"] = 1.5;um["lemon"] = 2.0;um["sugar"] = 0.8;// 遍历for (auto e : um){cout << e.first << ": " << e.second << endl;}
}
运行结果

(2)利用 [] 运算符重载函数进行修改
void test_unordered()
{// 构造对象unordered_map<string, double> um;// 利用[]运算符重载函数进行插入um["apple"] = 1.5;um["lemon"] = 2.0;um["sugar"] = 0.8;// 利用[]运算符重载函数修改valueum["apple"] = 8.88;// 遍历for (auto e : um){cout << e.first << ": " << e.second << endl;}
}
运行结果

总结:
- 若当前容器中已有键值为 key 的键值对,则返回该键值对 value 的引用。
- 若当前容器中没有键值为 key 的键值对,则先插入键值对
<key, value()>,然后再返回该键值对中 value 的引用。
🍅 find
在容器中搜索以 k 为键的元素,如果找到它,就返回一个迭代器,否则就返回 unordered_map::end(容器末端之前的元素)的迭代器。

代码示例
void test_unordered()
{// 构造对象unordered_map<string, double> um;// 利用[]运算符重载函数进行插入um["mom"] = 5.4;um["dad"] = 6.1;um["bro"] = 5.9;// 查找"dad"auto pos = um.find("dad");if (pos != um.end()){cout << pos->first << " is " << pos->second;}else{cout << "not found" << endl;}
}
运行结果

🍅 erase
从 unordered_map 容器中移除单个元素或一组元素([first,last))。
通过调用每个元素的析构函数,这有效地减少了容器的大小。

(1)从容器中删除单个元素(直接传要删除的元素)
void test_unordered()
{// 构造对象unordered_map<string, string> um;// 填充容器um["U.S."] = "Washington";um["U.K."] = "London";um["France"] = "Paris";um["Russia"] = "Moscow";um["China"] = "Beijing";um["Germany"] = "Berlin";um["Japan"] = "Tokyo";// 直接删除"Japan"um.erase("Japan");// 遍历for (auto e : um){cout << e.first << ": " << e.second << endl;}}
运行结果

(2)从容器中删除单个元素(搭配 find 使用)
void test_unordered()
{// 构造对象unordered_map<string, string> um;// 填充容器um["U.S."] = "Washington";um["U.K."] = "London";um["France"] = "Paris";um["Russia"] = "Moscow";um["China"] = "Beijing";um["Germany"] = "Berlin";um["Japan"] = "Tokyo";// 查找"Russia"的位置auto pos = um.find("Russia");if (pos != um.end()){um.erase(pos);cout << "delete success" << endl;}else{cout << "not found" << endl;}
}
运行结果

(3)从容器中删除一组元素(搭配 find 使用)
void test_unordered()
{// 构造对象unordered_map<string, string> um;// 填充容器um["U.S."] = "Washington";um["U.K."] = "London";um["France"] = "Paris";um["Russia"] = "Moscow";um["China"] = "Beijing";um["Germany"] = "Berlin";um["Japan"] = "Tokyo";// 查找"France"的位置auto pos = um.find("France");// 删除从"France"开始后面所有的元素um.erase(pos, um.end());// 遍历for (auto e : um){cout << e.first << ": " << e.second << endl;}
}
运行结果

🍅 size
返回 unordered_map 容器中的元素数量。

代码示例
void test_unordered()
{// 构造对象unordered_map<string, double> um = { {"milk", 2.30}, {"potatoes", 1.90}, {"eggs", 0.40} };cout << "size: " << um.size() << endl;// 插入重复元素um["milk"] = 5.80;cout << "size: " << um.size() << endl;
}
运行结果

🍅 empty
返回一个 bool 值,指示 unordered_map 容器是否为空,即其大小是否为 0。
这个函数不会以任何方式修改容器的内容。

代码示例
void test_unordered()
{unordered_map<int, int> um1; // 构造空容器unordered_map<int, int> um2 = { {1,10},{2,20},{3,30} }; // 构造非空容器// um1是空容器,所以结果为真cout << "um1 " << (um1.empty() ? "is empty" : "is not empty") << endl;// um2不是空容器,所以结果为假cout << "um2 " << (um2.empty() ? "is empty" : "is not empty") << endl;
}
运行结果

🍅 clear
unordered_map 容器中的所有元素都将被删除,会去调用它们的析构函数,并将它们从容器中移除,使容器的大小为 0。

代码示例
void test_unordered()
{// 初始化容器unordered_map<string, string> um1 = {{"house","maison"},{"car","voiture"},{"grapefruit","pamplemousse"}};// 清空容器um1.clear();// 重新插入数据um1["hello"] = "bonjour";um1["sun"] = "soleil";// 遍历for (auto& x : um1){cout << x.first << "=" << x.second << endl;}
}
运行结果

🍅 swap
通过 ump 的内容交换容器的内容,ump 是另一个包含相同类型元素的 unordered_map 对象,大小可能不同。
这个函数在容器之间交换指向数据的内部指针,而不实际对单个元素执行任何复制或移动,允许常量时间执行,无论大小如何。

代码示例
void test_unordered()
{// 初始化um1和um2容器unordered_map<string, string>um1 = { {"Star Wars","G"},{"Alien","R"} },um2 = { {"Inception","C"},{"Donnie Darko","R"} };// 交换两个容器的内容um1.swap(um2);// 遍历um1cout << "um1: ";for (auto& x : um1){cout << x.first << "-" << x.second << ", ";}cout << endl;// 遍历um2cout << "um2: ";for (auto& x : um2){cout << x.first << "-" << x.second << ", ";}
}
运行结果

🍅 count
在容器中搜索键为 k 的元素,并返回找到的元素数。
因为 unordered_map 容器不允许重复键,这意味着如果容器中存在具有该键的元素,则函数实际返回 1,否则返回 0。

代码示例
void test_unordered()
{// 初始化容器unordered_map<string, double> um = { {"Burger",2.99}, {"Fries",1.99}, {"Soda",1.50} };// 在um中查找下列的数据for (auto& x : { "Burger","Pizza","Salad","Soda" }) {if (um.count(x) > 0)std::cout << "um has " << x << std::endl;elsestd::cout << "um has no " << x << std::endl;}
}
运行结果

2. unordered_multimap的介绍和使用
unordered_multimap 的介绍:
- multimap 是一种关联容器,它存储由键值和映射值组合而成的元素,很像 unordered_map 容器,但是允许不同的元素具有等价的键。
- 在 unordered_multimap 中,键值通常用于唯一标识元素,而映射值是一个对象,其内容与该键相关联。键和映射值的类型可能不同。
- 在内部,unordered_multimap 中的元素不会根据它们的键值或映射值以任何特定的顺序进行排序,而是根据它们的散列值将它们组织到 bucket中,以允许直接通过键值快速访问单个元素(平均时间复杂度恒定)。
- 具有等效键的元素被分组在同一个 bucket 中,并且迭代器可以遍历所有这些元素。
- 容器中的迭代器至少是前向迭代器。
注意,这个容器不是在它自己的头文件中定义的,而是与 unordered_map 共享头文件 <unordered_map>。
🍑 unordered_multimap的使用
unordered_multimap 容器与 unordered_map 容器的底层数据结构是一样的,都是哈希表。
其次,它们所提供的成员函数的接口都是基本一致的,这两种容器唯一的区别就是,unordered_multimap 容器允许键值冗余,即 unordered_multimap 容器当中存储的键值对的 key 值是可以重复的。
其次,由于 unordered_multimap 容器允许键值对的键值冗余,调用 [] 运算符重载函数时,应该返回键值为 key 的哪一个键值对的 value 的引用存在歧义,因此在 unordered_multimap 容器当中没有实现 [] 运算符重载函数。

代码示例
void test_unordered()
{// 初始化容器unordered_multimap<int, string> umm;// 插入键值对,允许重复umm.insert(make_pair(2023, "跑步"));umm.insert({ 2023, "打球" });umm.insert({ 2023,"玩游戏" });// 遍历ummfor (auto x : umm){cout << x.first << ": " << x.second << endl;}
}
可以看到,key 是可以重复的。

另外,它和 unordered_map 容器所提供的成员函数的接口都是基本一致的,所以就不全部列举了,只列举几个稍微有点小差别的函数接口。
🍅 find
在容器中搜索以 key 为键的元素,如果找到,则返回该元素的迭代器,否则返回 unordered_multimap::end(超出容器末端的元素)的迭代器。
也就是返回底层哈希表中第一个找到的键值为 key 的键值对的迭代器。

代码示例
void test_unordered()
{// 初始化容器unordered_multimap<string, string> umm;// 插入键值对,允许重复umm.insert({ "mom", "妈妈" });umm.insert({ "mom", "母亲" });umm.insert({ "dad", "父亲" });umm.insert({ "bro", "兄弟" });// 查找第一个"mom"的key,并输出对应的valuecout << "one of the values for 'mom' is: ";cout << umm.find("mom")->second;
}
运行结果

🍅 count
在容器中搜索键为 k 的元素,并返回找到的元素个数。

代码示例
void test_unordered()
{// 初始化容器unordered_multimap<string, string> umm = {{"orange","FL"},{"strawberry","LA"},{"strawberry","OK"},{"pumpkin","NH"} };// 统计下面三个单词在容器中出现的次数for (auto& x : { "orange","lemon","strawberry" }) {cout << x << ": " << umm.count(x) << " 次" << endl;}
}
运行结果

相关文章:
C++STL剖析(九)—— unordered_map和unordered_multimap的概念和使用
文章目录1. unordered_map的介绍和使用🍑 unordered_map的构造🍑 unordered_map的使用🍅 insert🍅 operator[ ]🍅 find🍅 erase🍅 size🍅 empty🍅 clear🍅 sw…...
Android无菜单键,如何触发onCreateOptionsMenu(Menu menu)
文章目录小结问题及解决无法触发onCreateOptionsMenu(Menu menu)修改配置文件解决使用一个按钮来触发其它办法参考小结 现在的Android有三个键: 任务键,Home键,返回键,也就是没有菜单键了,那么如何如何触发onCreateOp…...
“黑洞”竟是外星人的量子计算机?
宇宙中的黑洞可以用作终极量子计算机,我们可以从中探索它们的特征。(图片来源:网络)我们完全有理由怀疑生命在我们的宇宙中很常见,但是为什么我们从未发现过其他生命存在的迹象?这个问题几乎自现代天文学诞…...
计算机网络入门
一,计算机网络在信息时代中的作用 21世纪的一些重要特征就是数字化,网络化和信息化,它是一个以网络为核心的信息时代。有三类大家很熟悉的网络,即电信网络,有线电视网络和计算机网络。按照最初的服务分工,…...
网络安全-内网DNS劫持-ettercap
网络安全-内网DNS劫持-ettercap 前言 一,我也是初学者记录的笔记 二,可能有错误的地方,请谨慎 三,欢迎各路大神指教 四,任何文章仅作为学习使用 五,学习网络安全知识请勿适用于违法行为 学习网络安全知识请…...
synchronized和Lock的区别
synchronized和lock的区别 synchronized和Lock,我已经通过源码级别的介绍过了,下面我们来总结下他们的区别 区别: 1.synchronized是关键字,Lock是接口,synchronized是JVM层实现,Lock是JDK中JUC包下的实现;…...
SpringBoot 指标监控 Actuator
Spring Boot Actuator为 Micrometer 提供了依赖管理和自动配置,Micrometer是一个支持 众多监控系统 的应用程序指标接口 该功能与:java\jdk\bin 下的 Jconsole 功能雷同 1、pom文件中引入依赖(使用的springboot是2.7.2) <dep…...
面试浅谈之十大排序算法
面试浅谈之十大排序算法 HELLO,各位博友好,我是阿呆 🙈🙈🙈 这里是面试浅谈系列,收录在专栏面试中 😜😜😜 本系列将记录一些阿呆个人整理的面试题 🏃&…...
LeetCode-1250. 检查「好数组」【数论,裴蜀定理】
LeetCode-1250. 检查「好数组」【数论,裴蜀定理】题目描述:解题思路一:裴蜀定理是:a*xb*y1。其中a,b是数组中的数,x,y是任意整数。如果a,b互质那么一定有解。问题即转换为寻找互质的数。解题思路二:简化代码…...
【Linux】NTP时间同步服务与NFS网络文件共享存储服务器(配置、测试)
一、NTP时间同步服务1、NTP介绍NTP服务器【Network Time Protocol(NTP)】是用来使计算机时间同步化的一种协议,它可以使计机对其服务器或时钟源(如石英钟,GPS等等)做同步化,它可以提供高精准度的时间校正&a…...
windows下php连接oracle安装oci8扩展报错(PHP Startup: Unable to load dynamic library ‘oci8_11g‘)
记录一下php7.29安装oci8的艰苦过程,简直就是唐僧西天取经历经九九八十一难。 使用的是phpstudy_pro安装的ph扩展wnmp环境下; 1 、安装oralce Instant Client 首先,安装oci8和pdo_oci扩展依赖的Oracle client。了解到需要连接的Oracle版…...
TensorRT的功能
TensorRT的功能 文章目录TensorRT的功能2.1. C and Python APIs2.2. The Programming Model2.2.2. The Runtime Phase2.3. Plugins2.4. Types and Precision2.5. Quantization2.6. Tensors and Data Formats2.7. Dynamic Shapes2.8. DLA2.9. Updating Weights2.10. trtexec本章…...
433MHz无线通信--模块RXB90
1、接收模块RXB90简介 两个数据输出是联通的。 2、自定义一个编码解码规则 组数据为“0x88 0x03 0xBD 0xB6”。 3、发射模块 如何使用示波器得到捕捉一个周期的图像? 通过date引脚连接示波器CH1,以及示波器探针的接地端接芯片的GND,分…...
Seata源码学习(三)-2PC核心源码解读
Seata源码分析-2PC核心源码解读 2PC提交源码流程 上节课我们分析到了GlobalTransactionalInterceptor全局事务拦截器,一旦执行拦截器,我们就会进入到其中的invoke方法,在这其中会做一些GlobalTransactional注解的判断,如果有注解…...
IO流概述
🏡个人主页 : 守夜人st 🚀系列专栏:Java …持续更新中敬请关注… 🙉博主简介:软件工程专业,在校学生,写博客是为了总结回顾一些所学知识点 目录IO流概述IO 流的分类总结流的四大类字…...
【node.js】node.js的安装和配置
文章目录前言下载和安装Path环境变量测试推荐插件总结前言 Node.js是一个在服务器端可以解析和执行JavaScript代码的运行环境,也可以说是一个运行时平台,仍然使用JavaScript作为开发语言,但是提供了一些功能性的API。 下载和安装 Node.js的官…...
Python优化算法—遗传算法
Python优化算法—遗传算法一、前言二、安装三、遗传算法3.1 自定义函数3.2 遗传算法进行整数规划3.3 遗传算法用于旅行商问题3.4 使用遗传算法进行曲线拟合一、前言 优化算法,尤其是启发式的仿生智能算法在最近很火,它适用于解决管理学,运筹…...
数据埋点(Data buried point)的应用价值剖析
一、什么是数据埋点?数据埋点指在应用中特定的流程中收集一些信息,用来跟踪应用使用的状况,后续用来进一步优化产品或是提供运营的数据支撑。比如访问数(Visits),访客数(Visitor),停…...
一文弄懂硬链接、软链接、复制的区别
复制 命令:cp file1 file2 作用:实现对file1的一个拷贝。 限制:可以跨分区,文件夹有效。 效果:修改file1,对file2无影响;修改file2,对file1无影响。删除file1,对file…...
界面组件Telerik ThemeBuilder R1 2023开创应用主题研发新方式!
Telerik DevCraft包含一个完整的产品栈来构建您下一个Web、移动和桌面应用程序。它使用HTML和每个.NET平台的UI库,加快开发速度。Telerik DevCraft提供最完整的工具箱,用于构建现代和面向未来的业务应用程序,目前提供UI for ASP.NET包含一个完…...
深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...
相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...
高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...
【笔记】WSL 中 Rust 安装与测试完整记录
#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统:Ubuntu 24.04 LTS (WSL2)架构:x86_64 (GNU/Linux)Rust 版本:rustc 1.87.0 (2025-05-09)Cargo 版本:cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...
掌握 HTTP 请求:理解 cURL GET 语法
cURL 是一个强大的命令行工具,用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中,cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
全面解析数据库:从基础概念到前沿应用
在数字化时代,数据已成为企业和社会发展的核心资产,而数据库作为存储、管理和处理数据的关键工具,在各个领域发挥着举足轻重的作用。从电商平台的商品信息管理,到社交网络的用户数据存储,再到金融行业的交易记录处理&a…...
绕过 Xcode?使用 Appuploader和主流工具实现 iOS 上架自动化
iOS 应用的发布流程一直是开发链路中最“苹果味”的环节:强依赖 Xcode、必须使用 macOS、各种证书和描述文件配置……对很多跨平台开发者来说,这一套流程并不友好。 特别是当你的项目主要在 Windows 或 Linux 下开发(例如 Flutter、React Na…...
AxureRP-Pro-Beta-Setup_114413.exe (6.0.0.2887)
Name:3ddown Serial:FiCGEezgdGoYILo8U/2MFyCWj0jZoJc/sziRRj2/ENvtEq7w1RH97k5MWctqVHA 注册用户名:Axure 序列号:8t3Yk/zu4cX601/seX6wBZgYRVj/lkC2PICCdO4sFKCCLx8mcCnccoylVb40lP...
yaml读取写入常见错误 (‘cannot represent an object‘, 117)
错误一:yaml.representer.RepresenterError: (‘cannot represent an object’, 117) 出现这个问题一直没找到原因,后面把yaml.safe_dump直接替换成yaml.dump,确实能保存,但出现乱码: 放弃yaml.dump,又切…...
