「C++笔记」unordered_map:哈希化的无序映射函数(键值对)
unordered_map 是 C++ 中一个经过哈希函数(Hash)处理的映射(map)容器。
本文中的
map和set是差不多的,unordered_map与unordered_set也是对应的。所以不再单独写一篇了。
这里的内容建议看完本文之后再回过头来看
二者虽然都有两个属性,但是程序员定义的时候数目不一样。
set是一种属性的容器,就像字典你定好“字”,页数是后面放的位置确定的。但是map是由两个属性确定的,所以也被称为键值对(key-value pairs)。
此外,unordered_set官方不建议修改元素值,因为修改之后,哈希值可能会发生变化,这样就出问题了。需要的话,删除再加就行了。但是unordered_map并没有这种提示。
为什么会有个无序的map
据《A Tour of C++ Third Edition》中描述,使用unordered_map而非map是因为在很多情况下,使用处理过的数据查询速度要比有序的快很多。其实这很容易理解,不过这里要先说明一下map是什么样的。
C++ 中的
map其实就是某些语言里的字典(dictionary)、关联数组(associative array)。
map 实际上是一个平衡二叉树(通常会使用红黑树),如下:

二叉树的查询时间是 O ( log ( n ) ) O(\log(n)) O(log(n)),假设有 1000000 个元素,那么最多只要 20 步就能找到这个元素。
这导致了一个现象:在很多时候,经过哈希函数处理的元素排列要比顺序的元素排列快很多。
经过哈希函数处理的元素排列是乱序的,这也是函数名中的“unordered”的由来。
unordered_map其实就是个哈希表。
举个例子,一个 1000000 个元素序列是升序的,那么如果查询的内容大多是较大的数,实际查询次数基本上都会超过 10 次。而经过哈希函数处理的乱序序列可能有的不足 10 次,有的超过 10 次,会比较平均。
正因如此,C++ 搞了个unordered_map避免这种问题。unordered_map结构如下:

unordered_map是通过标准库<hash>实现的,这部分内容你可以看看书中的内容,Bjarne Stroustrup 进行了一些简单地说明。书中基本上在强调找到一个好的 hash 函数是核心,因为只有这个函数好(适合要应用的数据), 乱序才能比顺序快。
举个🌰(使用方法)
下面是官方文档中的一个例子,个人感觉非常全面,就不再自己想了。那么就通过这个例子来说明一下如何使用unordered_map。
头文件如下:
#include <iostream>
#include <string>
#include <unordered_map>
在main()主函数中,首先创建一个unordered_map,两个属性都是字符串,拥有3个元素:
std::unordered_map<std::string, std::string> u =
{{"RED", "#FF0000"},{"GREEN", "#00FF00"}, {"BLUE", "#0000FF"}
};
接下来官方声明了一个lambda帮助函数(Helper lambda function)来打印键值对,这样可以大大减少后续输出时的代码量:
auto print_key_value = [](const auto& key, const auto& value)
{std::cout << "Key:[" << key << "] Value:[" << value << "]\n";
};
接下来有两种打印方式:第一种是普通的,第二种是 C++17 的结构化绑定(structured binding),个人推荐第二种:
for (const std::pair<const std::string, std::string>& n : u)print_key_value(n.first, n.second);for (const auto& [key, value] : u)print_key_value(key, value);
此时输出为:
Key:[BLUE] Value:[#0000FF]
Key:[GREEN] Value:[#00FF00]
Key:[RED] Value:[#FF0000]
如果想给这个unordered_map添加两个新的键值对,那么直接使用下面的方法就行:
u["BLACK"] = "#000000";
u["WHITE"] = "#FFFFFF";
这样就已经添加了,你可以打印一下看看,输出如下:
Key:[BLACK] Value:[#000000] <-----这个是新插入的
Key:[BLUE] Value:[#0000FF]
Key:[WHITE] Value:[#FFFFFF] <-----这个是新插入的
Key:[GREEN] Value:[#00FF00]
Key:[RED] Value:[#FF0000]
这里你可以看到,BLACK和WHITE并不是按照顺序插入到最后的,这里体现了它的“unordered”,而这是它的哈希函数做的。
除此之外,如果你对一个不存在的键(key)使用运算符[],那么会插入一个新的键值对:
print_key_value("new_key", u["new_key"]);
执行完这行代码之后,如果你想输出请使用auto类型,因为这里的键值对里的值并没有设置,如果使用前面的输出代码可能会报错(不过这个例子并没有出现错误),这里官方输出代码如下:
for (const auto& n : u)print_key_value(n.first, n.second);
此时输出如下:
Key:[new_key] Value:[] <-----这个是新插入的
Key:[GREEN] Value:[#00FF00]
Key:[BLACK] Value:[#000000]
Key:[BLUE] Value:[#0000FF]
Key:[WHITE] Value:[#FFFFFF]
Key:[RED] Value:[#FF0000]
如果你想借此机会插入一个键值对,可以使用下面的代码:
print_key_value("new_key", u["new_key"]="#123456");for (const auto& n : u)print_key_value(n.first, n.second);
此时输出为:
Key:[new_key] Value:[#123456] <-----这个是新插入的
Key:[GREEN] Value:[#00FF00]
Key:[BLACK] Value:[#000000]
Key:[BLUE] Value:[#0000FF]
Key:[WHITE] Value:[#FFFFFF]
Key:[RED] Value:[#FF0000]
需要注意不能写成下面这样,因为是[]操作符实现新建键值对的,而这样没有使用[]:
print_key_value("new_key", u["#123456");for (const auto& n : u)print_key_value(n.first, n.second);
此时输出结果为:
Key:[BLACK] Value:[#000000] <-----这个是新插入的
Key:[BLUE] Value:[#0000FF]
Key:[WHITE] Value:[#FFFFFF]
Key:[GREEN] Value:[#00FF00]
Key:[RED] Value:[#FF0000]
可以看到值并不是我们想要的#123456。
完整代码
#include <iostream>
#include <string>
#include <unordered_map>int main()
{// 创建一个unordered_map,两个属性都是字符串,拥有3个元素。std::unordered_map<std::string, std::string> u ={{"RED", "#FF0000"},{"GREEN", "#00FF00"},{"BLUE", "#0000FF"}};//print_key_value是一个lambda帮助函数(Helper lambda function)用来打印键值对//这样可以大大减少后续输出时的代码量auto print_key_value = [](const auto& key, const auto& value){std::cout << "Key:[" << key << "] Value:[" << value << "]\n";};std::cout << "迭代并打印unordered_map的键值对,并且显示其类型:\n";for (const std::pair<const std::string, std::string>& n : u)print_key_value(n.first, n.second);std::cout << "\n使用C++17结构化绑定(structured binding)迭代和打印键值对:\n";for (const auto& [key, value] : u)print_key_value(key, value);// 向unordered_map添加两个新条目u["BLACK"] = "#000000";u["WHITE"] = "#FFFFFF";for (const auto& [key, value] : u)print_key_value(key, value);std::cout << "\n通过键(key)输出值:\n""RED的HEX:[" << u["RED"] << "]\n""BLACK的HEX:[" << u["BLACK"] << "]\n\n";std::cout << "对不存在的键(key)使用运算符[]插入新的键值对:\n";print_key_value("new_key", u["new_key"]);std::cout << "\n使用`auto`类型迭代打印键值对;“new_key现在是映射中的键(key):\n";for (const auto& n : u)print_key_value(n.first, n.second);
}
希望能帮到有需要的人~
参考资料
《A Tour of C++ Third Edition》:6.5.6 hash<>,12.6 unordered_map。
C++ unordered_set 和 unordered_map 的中文官方文档,很多本文没有提到的功能都可以自行查看这里:
std::unordered_set - cppreference.com
std::unordered_map- cppreference.com
相关文章:
「C++笔记」unordered_map:哈希化的无序映射函数(键值对)
unordered_map 是 C 中一个经过哈希函数(Hash)处理的映射(map)容器。 本文中的map和set是差不多的,unordered_map与unordered_set也是对应的。所以不再单独写一篇了。 这里的内容建议看完本文之后再回过头来看 二者虽然…...
Linux 安装jdk
1、官网下载jdk https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html2、以tar包为例,在window或者Linux解压都可以,这里直接在win解压了,上传到服务器 3、在/usr/local/ 创建jdk目录,将jdk上传到…...
asp.net core 发布到iis后,一直500.19,IIS设置没问题,安装了sdk,文件夹权限都有,还是报错
原因就是没有安装ASP.NET Core 9.0 Runtime (v9.0.0) - Windows Hosting Bundle,我是只安装了.net core的sdk,下面介绍下sdk和hosting bundle的关系 在 .NET Core 和 ASP.NET Core 的开发中,SDK(Software Development Kit&#x…...
【Go】运行自己的第一个Go程序
运行自己的第一个Go程序 一、Go语言的安装Go环境安装查看是否安装成功配置GOPROXY(代理) 二、Goland安装三、Goland破解四、新建项目 开一篇专栏记录学习Go的过程,一门新语言从hello world开始,这篇文章详细讲解Go语言环境搭建及hello world实现 一、Go语…...
qt qss文件的使用
qt样式的修改方式 一 通过ui界面的改变样式表来直接修改显示效果。 不推荐,其他人不好修改,不够直观,不易维护。 二 通过setStyleSheet接口修改。 一般,界面很少的时候可以使用。一旦界面多起来,代码部分就显得杂乱…...
【管道——二分+区间合并】
题目 思路 区间合并 1、按照左端点排序2、遍历窗口,若窗口非法,继续遍历;否则执行33、若是第一个窗口,设定合并结果初值,判断结果左端点是否造成“起点过大”,是,FALSE退出;否则执行…...
宽带、光猫、路由器、WiFi、光纤之间的关系
1、宽带(Broadband) 1.1 宽带的定义宽带指的是一种高速互联网接入技术,通常包括ADSL、光纤、4G/5G等不同类型的接入方式。宽带的关键特点是能够提供较高的数据传输速率,使得用户可以享受到稳定的上网体验。 1.2 宽带的作用宽带是…...
如何排查 Apache Doris 中 “Failed to commit txn“ 导入失败问题?
今天来聊聊 Doris 数据导入那些事儿。你是不是在数据导入的时候遇到各种状况,让人头疼不已?别担心,这篇文章给你答案! 在 Doris 的版本里,< 2.0.3 的时候,数据迁移存在一些已知的问题,比如可…...
回归预测 | MATLAB实现CNN-GRU卷积门控循环单元多输入单输出回归预测
回归预测 | MATLAB实现CNN-GRU卷积门控循环单元多输入单输出回归预测 目录 回归预测 | MATLAB实现CNN-GRU卷积门控循环单元多输入单输出回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 MATLAB实现CNN-GRU卷积门控循环单元多输入单输出回归预测 数据准备&#x…...
HCIA-Access V2.5_7_3_XG(S)原理_关键技术
为什么需要测距 因为上行链路只有一根纤,而且每一个ONU到OLT的距离是不一样的,虽然上行通过TDMA技术,让每一个ONU在不同的时间段发送数据,但是仍然有可能在同一时刻到达分光器,产生数据冲突。 有测距的信元传输 所以为了避免碰撞冲突,通过ONU在注册的时候就会启动测距…...
leetcode hot 100 不同路径
62. 不同路径 已解答 中等 相关标签 相关企业 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )…...
智慧工地解决方案 1
建设背景与挑战 工地施工现场环境复杂,人员管理难度大,多工种交叉作业导致管理混乱,事故频发。传统管理方式难以实现科学、有效、集中式的管理,特别是在环境复杂、地点分散的情况下,监管困难,取证复杂。施…...
LeetCode -Hot100 - 53. 最大子数组和
前言 本专栏主要通过“LeetCode 热题100”,来捡起自己本科阶段的算法知识与技巧。语言主要使用c/java。如果同样正在练习LeetCode 热题100的朋友欢迎关注或订阅本专栏。有疑问欢迎留言交流~ 题目描述 题目链接 示例 1: 输入:nums [-2,1…...
php 多进程那点事,用 swoole 如何解决呢 ?
在 PHP 中,多进程的处理通常会遇到一些挑战,比如资源共享、进程间通信、性能优化等。Swoole 是一个高性能的协程和多进程框架,旨在为 PHP 提供异步、并发、协程等功能,解决了传统 PHP 环境中的多进程管理问题。通过使用 Swoole&am…...
探索AI在地质科研绘图中的应用:ChatGPT与Midjourney绘图流程与效果对比
文章目录 个人感受一、AI绘图流程1.1 Midjourney(1)环境配置(2)生成prompt(3)完善prompt(4)开始绘图(5)后处理 1.2 ChatGPT不合理的出图结果解决方案 二、主题…...
【竞技宝】CS2:HLTV 2024 TOP11-w0nderful
北京时间2025年1月4日,HLTV年度选手排名正在持续公布中,今日凌晨正式公布了今年的TOP11为NAVI战队的w0nderful。 选手简介 w0nderful是一名来自于乌克兰的CS选手,现年20岁,目前在比赛中司职狙击手。w0nderful于2020年开启了自己的…...
Lua迭代器如何使用?
在Lua中,迭代器是一种用于遍历集合元素的重要工具。掌握迭代器的使用方法,对于提高Lua编程的效率和代码的可读性具有重要意义。 1.迭代器概述 12.1.1 迭代器介绍 迭代器是一种设计模式,它提供了一种访问集合元素的方法,而不需要…...
qt中如何判断字符串是否为数字,整数,浮点数?
在 Qt 中,可以使用多种方法来判断字符串是否为数字、整数或浮点数。Qt 提供了一些方便的字符串和数值处理函数,可以帮助你实现这些判断。以下是几种常见的方法: 1. 使用 QRegularExpression Qt 提供了 QRegularExpression 类,可…...
Oracle sql developer and Toad for Oracle set start DBMS output
Oracle sql developer Toad for Oracle...
【踩坑】SparkSQL union/unionAll 函数的去重问题
【踩坑】SparkSQL union/unionAll 函数的去重问题 测试数据 case class Employee(first_name:String)val employeeDF1 spark.createDataset(Seq( Employee("Mary"), Employee("Mandy"),Employee("Kurt") )) val employeeDF2 spark.createDat…...
日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...
C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
招商蛇口 | 执笔CID,启幕低密生活新境
作为中国城市生长的力量,招商蛇口以“美好生活承载者”为使命,深耕全球111座城市,以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子,招商蛇口始终与城市发展同频共振,以建筑诠释对土地与生活的…...
前端调试HTTP状态码
1xx(信息类状态码) 这类状态码表示临时响应,需要客户端继续处理请求。 100 Continue 服务器已收到请求的初始部分,客户端应继续发送剩余部分。 2xx(成功类状态码) 表示请求已成功被服务器接收、理解并处…...
用鸿蒙HarmonyOS5实现国际象棋小游戏的过程
下面是一个基于鸿蒙OS (HarmonyOS) 的国际象棋小游戏的完整实现代码,使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├── …...
