【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.rhkb.cn/news/145943.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot的excel模板导出

Word的模板导出(参考&#xff1a;https://easyexcel.opensource.alibaba.com/docs/current/quickstart/fill) 创建有两个sheet的excel文件模板 将模板文件放入resource\templates/doc下使用 public void exportUavInfoExcel(HttpServletResponse response, CaseExportRPO cas…

NEON优化:性能优化经验总结

NEON优化&#xff1a;性能优化经验总结 1. 什么是 NEONArm Adv SIMD 历史 2. 寄存器3. NEON 命名方式4. 优化技巧5. 优化 NEON 代码(Armv7-A内容&#xff0c;但区别不大)5.1 优化 NEON 汇编代码5.1.1 Cortex-A 处理器之间的 NEON 管道差异5.1.2 内存访问优化 Reference: NEON优…

【MySQL进阶】--- 存储引擎的介绍

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【MySQL学习专栏】&#x1f388; 本专栏旨在分享学习MySQL的一点学习心得&#xff0c;欢迎大家在评论区讨论&#x1f48c; 目录 一、什么…

C++指针的使用

文章目录 1.C指针1.1 定义指针1.2 使用指针 2.空指针和野指针2.1 空指针2.2 野指针 3.指针所占空间4.使用const修饰指针4.1 const修饰指针4.2 const修饰常量4.3 const 既修饰指针也修饰常量 5.指针操作数组6.指针做函数参数7.使用指针知识实现冒泡排序 1.C指针 指针其实就是一…

ciscn_2019_s_9

ciscn_2019_s_9 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x8048000) RWX: Has RWX segments32位&#xff0c;啥也没开&#xff0c;开心愉悦写shellcode int pwn() {char s[24]; // [esp8…

cesium 雷达扫描 (波纹线性雷达扫描效果)

cesium 雷达扫描 (波纹线性雷达扫描效果) 1、实现方法 使用ellipse方法加载圆型,修改ellipse中material方法来实现效果 2、示例代码 2.1 <!DOCTYPE html> <html lang="en"><head>&l

UE学习记录06----根据Actor大小自适应相机位置

背景&#xff1a; staticMesh 会根据业务需要随时变化&#xff0c;然后通过staticMesh的大小自适应相机位置&#xff0c;捕捉画面用来预览该模型&#xff0c;使模型在画布中不会太大导致显示不全&#xff0c;也不会太小 参考&#xff1a; UE实现相机聚焦物体功能_右弦GISer的…

国庆10.1

用select实现服务器并发 ser #include <myhead.h> #define ERR_MSG(msg) do{\fprintf(stderr, "__%d__", __LINE__);\perror(msg);\ }while(0)#define PORT 8888 //端口号&#xff0c;范围1024~49151 #define IP "192.168.1.205" //本机…

【算法|贪心算法系列No.3】leetcode334. 递增的三元子序列

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…

【C语言】【结构体的位段】位段的内存分配及注意事项

1.什么是位段&#xff1a; struct A { int _a:2; int _b:5; int _c:10; int _d:30; };1.A就是一个位段类型的变量&#xff0c;位表示比特位&#xff0c;意思是 A中的变量申请内存的比特位数 比如 _a要占 2 个bit 2.位段的成员必须是 int ,unsigned int ,signed int 类型的&…

DataBinding双向绑定简介

一、简介 在Vue中使用的是MVVM架构。通过ViewModel可以实现M层和V层数据的双向绑定。Model层的数据发生变化后&#xff0c;会自动更新View层UI。UI层数据发生变化&#xff08;用户输入&#xff09;&#xff0c;可以驱动Model层的数据发生变化&#xff0c;借助于Vue框架中的View…

USART串口协议

通信接口 •通信的目的&#xff1a;将一个设备的数据传送到另一个设备&#xff0c;扩展硬件系统 • 通信协议&#xff1a;制定通信的规则&#xff0c;通信双方按照协议规则进行数据收发 全双工&#xff1a;指通信双方能够同时进行双向通信&#xff0c;一般来说&#xff0c;全双…

QT的ui设计中改变样式表的用法

在QT的ui设计中,我们右键会弹出一个改变样式表的选项,很多人不知道这个是干什么的。 首先我们来看下具体的界面 首先我们说一下这个功能具体是干嘛的, 我们在设置很多控件在界面上之后,常常都是使用系统默认的样式,但是当有些时候为了美化界面我们需要对一些控件进行美化…

计算机竞赛 深度学习手势识别 - yolo python opencv cnn 机器视觉

文章目录 0 前言1 课题背景2 卷积神经网络2.1卷积层2.2 池化层2.3 激活函数2.4 全连接层2.5 使用tensorflow中keras模块实现卷积神经网络 3 YOLOV53.1 网络架构图3.2 输入端3.3 基准网络3.4 Neck网络3.5 Head输出层 4 数据集准备4.1 数据标注简介4.2 数据保存 5 模型训练5.1 修…

数据结构:复杂度分析

目录 1 算法效率评估 1.1 实际测试 1.2 理论估算 2 迭代与递归 2.1 迭代 1. for 循环 2. while 循环 3. 嵌套循环 2.2 递归 1. 调用栈 2. 尾递归 3. 递归树 2.3 两者对比 3 时间复杂度 3.1 统计时间增长趋势 3.2 函数渐近上界…

SpringBoot整合RabbitMQ实现延迟队列功能

&#x1f468;&#x1f3fb;‍&#x1f4bb; 热爱摄影的程序员 &#x1f468;&#x1f3fb;‍&#x1f3a8; 喜欢编码的设计师 &#x1f9d5;&#x1f3fb; 擅长设计的剪辑师 &#x1f9d1;&#x1f3fb;‍&#x1f3eb; 一位高冷无情的编码爱好者 大家好&#xff0c;我是 DevO…

【vue3】toRef与toRefs的使用,toRef与ref的区别

假期第四篇&#xff0c;对于基础的知识点&#xff0c;我感觉自己还是很薄弱的。 趁着假期&#xff0c;再去复习一遍 1、toRef与toRefs 创建一个ref对象&#xff0c;其value值指向另一个对象中的某个属性 语法&#xff1a;const name toRef&#xff08;person,‘name’&#xf…

期权定价模型系列【7】:Barone-Adesi-Whaley定价模型

期权定价模型系列第7篇文章 1.前言 目前大连商品交易所、郑州商品交易所、以及上海期货交易所的所有商品期权都为美式期权&#xff0c;并且大商所的所有期权合约会根据BAW(Barone-Adesi-Whaley)美式期权定价模型计算新上市期权合约的挂牌基准价。 BAW模型(Barone-Adesi and W…

动态规划算法(1)--矩阵连乘和凸多边形剖分

目录 一、动态数组 1、创建动态数组 2、添加元素 3、删除修改元素 4、访问元素 5、返回数组长度 6、for each遍历数组 二、输入多个数字 1、正则表达式 2、has.next()方法 三、矩阵连乘 1、什么是矩阵连乘&#xff1f; 2、动态规划思路 3、手推m和s矩阵 4、完…

Vue之transition组件

Vue提供了transition组件&#xff0c;使用户可以更便捷地添加过渡动画效果。 transition组件 transition组件也是一个抽象组件&#xff0c;并不会渲染出真实dom。Vue会在其第一个真实子元素上添加过渡效果。 props render 这里将render分为两部分&#xff0c;第一部分界定真…