【C++】unordered_set、unordered_map的介绍及使用

unordered_set、unordered_map的介绍及使用

  • 一、unordered系列关联式容器
  • 二、unordered_map and unordered_multimap
    • 1、unordered_map的介绍
    • 2、unordered_map的使用
      • (1)定义
      • (2)接口使用
    • 3、unordered_multimap
  • 二、unordered_set and unordered_multiset
    • 1、unordered_set介绍
    • 2、unordered_set使用
      • (1)定义
      • (2)接口使用
    • 3、unordered_multiset
  • 三、map/set 和 unordered_map/unordered_set的区别


一、unordered系列关联式容器

在C++98中,STL提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到 l o g 2 N log_2 N log2N,即最差情况下需要比较红黑树的高度次,当树中的节点非常多时,查询效率也不理想。最好的查询是,进行很少的比较次数就能够将元素找到,因此在C++11中,STL又提供了4个unordered系列的关联式容器,这四个容器与红黑树结构的关联式容器使用方式基本类似,只是其底层结构不同

二、unordered_map and unordered_multimap

1、unordered_map的介绍

  1. unordered_map是存储<key, value>键值对的关联式容器,其允许通过keys快速的索引到与其对应的value。
  2. 在unordered_map中,键值通常用于惟一地标识元素,而映射值是一个对象,其内容与此键关联。键和映射值的类型可能不同
  3. 在内部,unordered_map没有对<kye, value>按照任何特定的顺序排序, 为了能在常数范围内找到key所对应的value,unordered_map将相同哈希值的键值对放在相同的桶中。
  4. unordered_map容器通过key访问单个元素要比map快,但它通常在遍历元素子集的范围迭代方面效率较低
  5. unordered_maps实现了直接访问操作符(operator[]),它允许使用key作为参数直接访问value。
  6. 它的迭代器至少是前向迭代器

2、unordered_map的使用

(1)定义

其定义方式如下:

void test_unordered_map1()
{// 构造一个空的key为int,value为double的unordered_mapunordered_map<int, double> um1;// 给um1赋上值um1.insert(make_pair(1, 1.1));um1.insert(make_pair(2, 2.2));um1.insert(make_pair(3, 3.3));um1.insert(make_pair(4, 4.4));// 拷贝构造unordered_map<int, double> um2(um1);// 迭代器区间拷贝um2的一段unordered_map<int, double> um3(um2.begin(), um2.end());// for循环打印一下um3,um3没问题则um1和um2都没问题for (auto& e : um3){cout << e.first<< "=>" << e.second << " ";}cout << endl;
}

(2)接口使用

成员函数功能
insert插入键值对
erase删除指定key的值的键值对
size获取容器中元素的个数
find查找指定key值的键值对
empty判断容器是否为空
clear清空当前容器
swap交换两个容器中的数据
count获取容器中指定key值的元素的个数
[]运算符重载的[]功能很强大,有插,改、找等功能
begin()获取容器中第一个元素的正向迭代器
end()获取容器中最后一个元素的下一个元素的正向迭代器的

重点讲一下[]:
1、若当前容器中已经存在着键值为key的键值对,则返回该键值对value的引用。
2、若当前容器中没有键值为key的键值对,则先插入键值对<key, value()>,然后再返回该键值对中value的引用。

下面直接看代码,关于上述所有的代码操作:

void test_unordered_map2()
{// 构造一个空的key为int,value为string的unordered_mapunordered_map<int, string> um1;// 插入方法一:构造匿名对象插入um1.insert(pair<int, string>(1, "111"));um1.insert(pair<int, string>(2, "222"));um1.insert(pair<int, string>(3, "333"));// 插入方法二:调用make_pair插入um1.insert(make_pair(4, "444"));um1.insert(make_pair(5, "555"));um1.insert(make_pair(6, "666"));// 插入方法三:用operator[]um1[7] = "777";um1[8] = "888";um1[9] = "999";um1[10] = "000";// 遍历方式一:利用迭代器进行遍历打印//unordered_map<int, string>::iterator it = um1.begin();auto it = um1.begin();while (it != um1.end()){cout << (*it).first << "=>" << (*it).second << " ";++it;}cout << endl; // 1=>111 2=>222 3=>333 4=>444 5=>555 6=>666 7=>777 8=>888 9=>999 10=>000// 遍历方法二:利用for循环进行遍历打印for (auto& e : um1){cout << e.first<< "=>" << e.second << " ";}cout << endl; // 1=>111 2=>222 3=>333 4=>444 5=>555 6=>666 7=>777 8=>888 9=>999 10=>000// 删除操作1:根据键值对key删除um1.erase(5);// 删除操作2:根据迭代器进行删除unordered_map<int, string>::iterator rit = um1.find(7); // 顺带使用键值对key就可以用find函数了if (rit != um1.end()){um1.erase(rit);}// 遍历打印一下,用for循环方便快捷一点for (auto& e : um1){cout << e.first << "=>" << e.second << " ";}cout << endl; // 1=>111 2=>222 3=>333 4=>444 6=>666 8=>888 9=>999 10=>000// 修改键值对:通过find获得迭代器进行修改auto pos = um1.find(1);if (pos != um1.end()){pos->second = "11/11";}// 修改键值对:通过operator[]运算符重载进行修改um1[2] = "22/22";// 打印一下for (auto& e : um1){cout << e.first << "=>" << e.second << " ";}cout << endl; // 1=>11/11 2=>22/22 3=>333 4=>444 6=>666 8=>888 9=>999 10=>000// 判空cout << um1.empty() << endl; // 0 -- 不空// 计算容器的大小cout << um1.size() << endl; // 8个// 计算容器中键值对的大小cout << um1.count(3) << endl; // 1// 交换两容器中的数据unordered_map<int, string> tmp{{11, "123"}, { 22, "345" }};um1.swap(tmp);for (auto& e : tmp){cout << "tmp=>" << " ";cout << e.first << "=>" << e.second << " ";}cout << endl; // tmp=> 1=>11/11 2=>22/22 3=>333 4=>444 6=>666 8=>888 9=>999 10=>000for (auto& e : um1){cout << "um1=>" << " ";cout << e.first << "=>" << e.second << " ";}cout << endl; // um1=> 11=>123 22=>345// 清空um1.clear();for (auto& e : um1){cout << e.first << "=>" << e.second << " ";}cout << endl;
}

3、unordered_multimap

这个容器与unordered_map基本一致,这两个的区别在于multimap允许键值对的冗余,也就是可以允许key和value有不同的值。

void test_unordered_map3()
{unordered_multimap<int, string> ummp1;ummp1.insert(make_pair(2023, "yes"));ummp1.insert(make_pair(2023, "no"));ummp1.insert(make_pair(2023, "before"));ummp1.insert(make_pair(2023, "now"));for (auto& e : ummp1){cout << e.first << "=>" << e.second << " ";}cout << endl;
}

还有三个不同:

1、unordered_map和unordered_multimap的find函数:

find函数功能
unordered_map返回键值为key的键值对的迭代器
unordered_multimap返回底层哈希表中第一个找到的键值为key的键值对的迭代器

2、count函数功能

count函数功能
unordered_map键值为key的键值对存在则返回1,不存在则返回0(find成员函数可替代)
unordered_multimap返回键值为key的键值对的个数(find成员函数不可替代)

3、operator[]函数功能

我们在unordered_multimap中是没有这个operator[]重载的,因为这个容器中是可以冗余的,所以我们不确定找的是哪一个,会导致很多的错误,所以我们的unordered_multimap是没有operator[]这个的!

二、unordered_set and unordered_multiset

1、unordered_set介绍

1、unordered_set是不按特定顺序存储键值的关联式容器,其允许通过键值快速的索引到对应的元素。
2、在unordered_set中,元素的值同时也是唯一地标识它的key。
3、在内部,unordered_set中的元素没有按照任何特定的顺序排序,为了能在常数范围内找到指定的key,unordered_set将相同哈希值的键值放在相同的桶中。
4、unordered_set容器通过key访问单个元素要比set快,但它通常在遍历元素子集的范围迭代方面效率较低。
5、它的迭代器至少是前向迭代器。

2、unordered_set使用

(1)定义

void test_unordered_set1()
{// 构造一个空壳的us1的unordered_set的容器unordered_set<int> us1;// 插入几个值us1.insert(1);us1.insert(2);us1.insert(3);us1.insert(4);// 拷贝构造unordered_set<int> us2(us1);// 迭代器区间构造unordered_set<int> us3(us2.begin(), us2.end());// for循环打印一下for (auto& e : us3){cout << e << " ";}cout << endl;
}

(2)接口使用

成员函数功能
insert插入指定元素
erase删除指定元素
size获取容器中元素的个数
find查找指定元素
empty判断容器是否为空
clear清空当前容器
swap交换两个容器中的数据
count获取容器中指定元素的个数
[]运算符重载的[]功能很强大,有插,改、找等功能
begin()获取容器中第一个元素的正向迭代器
end()获取容器中最后一个元素的下一个元素的正向迭代器的
void test_unordered_set2()
{// 先构造一个空的容器unordered_set<int> us1;// 插入元素(只有这一种插入法)us1.insert(1);us1.insert(2);us1.insert(3);us1.insert(1);us1.insert(4);us1.insert(5);// 遍历容器第一种方法:迭代器遍历unordered_set<int>::iterator it = us1.begin();while (it != us1.end()){cout << *it << " ";++it;}cout << endl; // 1 2 3 4 5// 遍历容器第二种方法:for循环for (auto& e : us1){cout << e << " ";}cout << endl; // 1 2 3 4 5// 删除元素的方式一:直接找到值进行删除us1.erase(1);// 删除元素的方法二:利用迭代器进行删除unordered_set<int>::iterator pos = us1.find(2);if (pos != us1.end()){us1.erase(pos);}// 打印一下for (auto& e : us1){cout << e << " ";}cout << endl; // 3 4 5// 判断容器是否为空cout << us1.empty() << endl; // 0// 获取值为3的个数cout << us1.count(3) << endl; // 1// 查看当前容器的容量cout << us1.size() << endl; // 3// 交换数据unordered_set<int> tmp{99, 88, 77, 66};us1.swap(tmp);// 打印一下for (auto& e : us1){cout << e << " ";}cout << endl; // 99 88 77 66 // 打印一下for (auto& e : tmp){cout << e << " ";}cout << endl; // 3 4 5// 清空us1.clear();// 打印一下for (auto& e : us1){cout << e << " ";}cout << endl;  //   
}

3、unordered_multiset

大致实现的功能与unordered_map相同,但唯一不同的一点是在于这个多功能的set是允许值进行重复的!

void test_unordered_set3()
{unordered_multiset<int> ums1;ums1.insert(1);ums1.insert(2);ums1.insert(4);ums1.insert(3);ums1.insert(1);ums1.insert(5);ums1.insert(2);ums1.insert(7);for (auto& e : ums1){cout << e << " ";}cout << endl;  // 1 1 2 2 3 4 5 7
}

这个多功能的set是相较于普通set来讲的count函数是返回的个数,而普通set的count函数是如果存在则返回1,不存在则返回0。

这个多功能set相较于普通set来讲的find函数是返回底层哈希表中第一个找到的键值为val的元素的迭代器,而普通set则是返回简单的key。

三、map/set 和 unordered_map/unordered_set的区别

在这里插入图片描述

性能测试来一波:

#include <iostream>
#include <set>
#include <unordered_set>
#include <time.h>
using namespace std;int main()
{int N = 1000;vector<int> v;v.reserve(N);srand((unsigned int)time(NULL));//随机生成N个数字for (int i = 0; i < N; i++){v.push_back(rand());}//将这N个数插入set容器set<int> s;clock_t begin1 = clock();for (auto e : v){s.insert(e);}clock_t end1 = clock();//将这N个数插入unordered_set容器unordered_set<int> us;clock_t begin2 = clock();for (auto e : v){us.insert(e);}clock_t end2 = clock();//分别输出插入set容器和unordered_set容器所用的时间cout << "set insert: " << end1 - begin1 << endl;cout << "unordered_set insert: " << end2 - begin2 << endl;//在set容器中查找这N个数clock_t begin3 = clock();for (auto e : v){s.find(e);}clock_t end3 = clock();//在unordered_set容器中查找这N个数clock_t begin4 = clock();for (auto e : v){us.find(e);}clock_t end4 = clock();//分别输出在set容器和unordered_set容器中查找这N个数所用的时间cout << "set find: " << end3 - begin3 << endl;cout << "unordered_set find: " << end4 - begin4 << endl;//将这N个数从set容器中删除clock_t begin5 = clock();for (auto e : v){s.erase(e);}clock_t end5 = clock();//将这N个数从unordered_set容器中删除clock_t begin6 = clock();for (auto e : v){us.erase(e);}clock_t end6 = clock();//分别输出将这N个数从set容器和unordered_set容器中删除所用的时间cout << "set erase: " << end5 - begin5 << endl;cout << "unordered_set erase: " << end6 - begin6 << endl;return 0;
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/146755.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【python海洋专题八】Cartopy画地形水深图的contourf填充间隔数调整

【python海洋专题八】Cartopy画地形水深图的contourf填充间隔数调整 article 有时候想把contourf的画面变得更细 此时&#xff0c;就需要增加填充间隔数 本期内容 1&#xff1a;contourf的填充个数改变 cf ax.contourf(lon, lat, ele[:, :], levelsnp.linspace(-9000,0,60…

【中秋国庆不断更】HarmonyOS对通知类消息的管理与发布通知(下)

一、发布进度条类型通知 进度条通知也是常见的通知类型&#xff0c;主要应用于文件下载、事务处理进度显示。HarmonyOS提供了进度条模板&#xff0c;发布通知应用设置好进度条模板的属性值&#xff0c;如模板名、模板数据&#xff0c;通过通知子系统发送到通知栏显示。 目前系统…

JS三大运行时全面对比:Node.js vs Bun vs Deno

全文约 5100 字&#xff0c;预计阅读需要 15 分钟。 JavaScript 运行时是指执行 JavaScript 代码的环境。目前&#xff0c;JavaScript 生态中有三大运行时&#xff1a;Node.js、Bun、Deno。老牌运行时 Node.js 的霸主地位正受到 Deno 和 Bun 的挑战&#xff0c;下面就来看看这…

设计模式1、单例模式 Singleton

解释说明&#xff1a;确保一个类只有一个实例&#xff0c;并提供一个全局访问点来访问这个唯一实例 要点如下 有且仅有一个实例 必须自行创建自己的唯一实例 必须给所有其他对象提供这一实例 具体实现要点如下 提供一个 private 构造函数&#xff08;防止外部调用而构造类的实例…

【COMP304 LEC3】

LEC 3 1. Contingent Formulas&#xff1a; 定义&#xff1a;Truth or falsity of a propositional formula depends on the truth/falsity of the atoms in the formula 例子&#xff1a;p ∧ q is true if both p and q are true, false otherwise.这里p和q就是atoms&…

paddle2.3-基于联邦学习实现FedAVg算法-CNN

目录 1. 联邦学习介绍 2. 实验流程 3. 数据加载 4. 模型构建 5. 数据采样函数 6. 模型训练 1. 联邦学习介绍 联邦学习是一种分布式机器学习方法&#xff0c;中心节点为server&#xff08;服务器&#xff09;&#xff0c;各分支节点为本地的client&#xff08;设备&#…

【精品】Springboot 接收发送日期类型的数据

问题 无法请求到后台&#xff0c;后台报错&#xff1a;[Failed to convert property value of type java.lang.String to required type java.time.LocalDateTime for property &#xff1a; 2023-10-02T09:26:16.06908:00 WARN 14296 --- [p-nio-80-exec-1] .w.s.m.s.Defaul…

跨类型文本文件,反序列化与类型转换的思考

文章目录 应用场景序列化 - 对象替换原内容&#xff0c;方便使用编写程序取得结果数组 序列化 - JSON 应用场景 在编写热更新的时候&#xff0c;我发现了一个古早的 ini 文件&#xff0c;记录了许多有用的数据 由于使用的语言年份较新&#xff0c;没有办法较好地对 ini 文件的…

Canal实现数据同步

1、Canal实现数据同步 canal可以用来监控数据库数据的变化&#xff0c;从而获得新增数据&#xff0c;或者修改的数据。 1.1 Canal工作原理 原理相对比较简单&#xff1a; 1、canal模拟mysql slave的交互协议&#xff0c;伪装自己为mysql slave&#xff0c;向mysql master发送…

图神经网络GNN(一)GraphEmbedding

DeepWalk 使用随机游走采样得到每个结点x的上下文信息&#xff0c;记作Context(x)。 SkipGram优化的目标函数&#xff1a;P(Context(x)|x;θ) θ argmax P(Context(x)|x;θ) DeepWalk这种GraphEmbedding方法是一种无监督方法&#xff0c;个人理解有点类似生成模型的Encoder过程…

树莓派CM4开启I2C与UART串口登录同时serial0映射到ttyS0 开启多串口

文章目录 前言1. 树莓派开启I2C与UART串口登录2. 开启多串口总结&#xff1a; 前言 最近用CM4的时候使用到了I2C以及多个UART的情况。 同时配置端口映射也存在部分问题。 这里集中记录一下。 1. 树莓派开启I2C与UART串口登录 输入指令sudo raspi-config 跳转到如下界面&#…

3D WEB轻量化引擎HOOPS助力3D测量应用蓬勃发展:效率、精度显著提升

在3D开发工具领域&#xff0c;Tech Soft 3D打造的HOOPS SDK已经崭露头角&#xff0c;成为了全球领先的3D领域开发工具提供商。HOOPS SDK包括四种不同的3D软件开发工具&#xff0c;已成为行业的翘楚。 其中&#xff0c;HOOPS Exchange以其CAD数据转换的能力脱颖而出&#xff0c…

Arm Cache学习资料大汇总

关键词&#xff1a;cache学习、mmu学习、cache资料、mmu资料、arm资料、armv8资料、armv9资料、 trustzone视频、tee视频、ATF视频、secureboot视频、安全启动视频、selinux视频&#xff0c;cache视频、mmu视频&#xff0c;armv8视频、armv9视频、FF-A视频、密码学视频、RME/CC…

前端开发网站推荐

每个人都会遇见那么一个人&#xff0c;永远无法忘却&#xff0c;也永远不能拥有。 以下是一些可以用来查找和比较前端框架的推荐网站&#xff1a; JavaScript框架比较&#xff1a; 这些网站提供了对不同JavaScript框架和库的详细比较和评估。 JavaScripting: 提供了大量的JavaS…

JavaScript高阶班之ES6 → ES11(八)

JavaScript高阶班之ES6 → ES11 1、ES6新特性1.1、let 关键字1.2、const关键字1.3、变量的解构赋值1.3.1、数组的解构赋值1.3.2、对象的解构赋值 1.4、模板字符串1.5、简化对象写法1.6、箭头函数1.7、函数参数默认值1.8、rest参数1.9、spread扩展运算符1.9.1、数组合并1.9.2、数…

上古神器:十六位应用程序 Debug 的基本使用

文章目录 参考环境上古神器 DebugBug 与 DebuggingDebugDebug 应用程序淘汰原因使用限制 DOSBox学习 Debug 的必要性DOSBox-X Debug 的基本使用命令 R查看寄存器的状态修改寄存器的内容 命令 D显示内存中的数据指定起始内存空间地址指定内存空间的范围 命令 A使用命令语法错误查…

第8章 Spring(二)

8.11 Spring 中哪些情况下,不能解决循环依赖问题 难度:★★ 重点:★★ 白话解析 有一下几种情况,循环依赖是不能解决的: 1、原型模式下的循环依赖没办法解决; 假设Girl中依赖了Boy,Boy中依赖了Girl;在实例化Girl的时候要注入Boy,此时没有Boy,因为是原型模式,每次都…

Konva离屏缓存

前言 cache实例方法定义在Node基类上&#xff0c;通过该方法可以实现图形缓存&#xff0c;在Konva中Stage、Layer、Group、Shape等所有容器类和图形类都直接或间接继承了Node基类&#xff0c;故而都可以使用缓存方法。本篇文章就是探讨Konva背后的缓存机制&#xff0c;版本是v…

8.3Jmeter使用json提取器提取数组值并循环(循环控制器)遍历使用

Jmeter使用json提取器提取数组值并循环遍历使用 响应返回值例如&#xff1a; {"code":0,"data":{"totalCount":11,"pageSize":100,"totalPage":1,"currPage":1,"list":[{"structuredId":&q…

计算机网络笔记 第二章 物理层

2.1 物理层概述 物理层要实现的功能 物理层接口特性 机械特性 形状和尺寸引脚数目和排列固定和锁定装置 电气特性 信号电压的范围阻抗匹配的情况传输速率距离限制 功能特性 -规定接口电缆的各条信号线的作用 过程特性 规定在信号线上传输比特流的一组操作过程&#xff0…