Learning C++ No.25【开散列封装unordered_set和unordered_map】

news2024/11/26 2:46:06

引言:

北京时间:2023/5/29/7:05,上星期更文一篇,且该篇博客在周三就写完了,所以充分体现,咱这个星期摆烂充分,哈哈哈!现在的内心情感没有以前那么从容了,这次摆的时间是有点久了,但本质影响不大,因为我现在还在码字,三天不学习,或者说是没有踏实学习,目前给我的感觉很难受,就像是好久好久没有学习过一样,感觉三天前学的东西,已经忘的差不多了,但,不慌,因为我们有写博客进行总结,可以让我们第一时间将相关知识回顾,所以这也是写博客最大的好处之一,并且在这三天的摆烂中,不是连续性的,而是间断性,可能这个间断性,也是我摆烂的重要原因之一,并且摆烂的过程还是那么朴实无华,王者荣耀,快4个月没玩,一开始玩的不怎样,后来手感越来越好,逐渐疯狂,一路连胜,把把c,这也可能就是为什么能持续摆烂的原因吧!So,简简单单,由于我们上篇博客的内容是哈希表的自我封装,所以该篇博客的内容就是unordered_set和unordered_map的封装 ,希望这不是我周末摆烂的开始,并且摆烂可以,但是一定需要在有一定的学习内容之后,充分反省,希望以后看到该篇博客的引言时,不是以今天这种较为落寞的情绪吧!

在这里插入图片描述

STL中有关unordered_set和unordered_map的知识

在上篇博客中,我们自己封装实现了哈希表,明白了许多有关哈希表的知识,如:哈希函数,哈希地址,哈希下标,哈希值等!那么哈希表有什么用呢?当我们谈到哈希表的用处之时,最好的回答方向就是从哈希表的优势出发,哈希表在查找和访问数据方面具有超高的效率(O(1)),就算是红黑树在查找方面也是远远不如,当然,不同的场景,红黑树和哈希表都各具风骚,否则肯定是一山不容二虎,其中一个早就被淘汰了,其中从之前我们使用红黑树封装set和map的博客中也能看出,红黑树在生活中的许多领域都应用广泛,所以人们特地的将红黑树进行了一定的封装,也就是set和map,同理,哈希表也被人们广泛使用,也被封装成了STL中的某种数据结构(关联式容器),也就是该篇博客的重点内容,unordered_set和unordered_map,所以接下来就让我们一起看看unordered_set和unordered_map的具体使用方法和自我封装吧!如下:

unordered_set和unordered_map的具体使用方法

unordered_set使用方法

unordered_set使用文档
通过文档我们可以看出,unordered_set和我们之前学习的set的使用方式是相同的,本质没有什么区别,所以这里我们不多做分析,具体直接看如下代码:
在这里插入图片描述
简简单单,同理就是插入、查找、删除这些基础接口和迭代器的使用,唯一值得注意的是:此时使用哈希表实现的unordered_set它不同于红黑树实现的set,一个是有序的,一个是无序的,当然,红黑树肯定是中序遍历有序的那一个,哈希表无序,且set是一个双向迭代器,而unordered_set是一个单向迭代器,具体为什么unordered_set设计成单向迭代器,而不设计成双向迭代器,原因如下:

  1. 对应数据在插入和删除的时候,可能会改变原哈希表中相关数据的链接关系,所以很难确保双向迭代器始终能够访问到对应的数据
  2. 因为哈希表中的数据是通过哈希地址控制,且哈希地址是通过哈希函数和对应的哈希值得到,所以哈希表中的数据都是随机无序存储,具有不可预测的性质
  3. 在哈希表结构中(开散列),数据之间是通过链式结构连接在一起的,所以我们可以直接通过对应的哈希地址去访问到对应的链表,再直接遍历链表,找到目标元素,而不需要按照固定的顺序去遍历整个哈希表,效率更高

unordered_map使用方法

unordered_map使用文档
多的不说,少的不唠,同理map使用方法,直接看代码,如下:
在这里插入图片描述
使用方法,同理map相关知识,且具体注意事项,在上述unordered_set已经强调,多了也没有,唯一值得注意的是和unordered_set最大的区别,也就是方括号运算符的使用,当然在map中方括号的实现和使用我们已经详细讲解过了,这里就不多加描述,接下来直接进入unordered_set和unordered_map的封装,如下代码所示:

unordered_set和unordered_map的封装

1.解决不同模型问题
第一点,同理红黑树实现set和map,还是数据类型问题,unordered_set和unordered_map也具有该方面的问题,如何使用同一份哈希表的代码同时实现unordered_set和unordered_map,类比红黑树实现set和map,这里依然使用泛型编程,当然也就是模板来解决该问题,基本原理就是将哈希表的哈希结点设计成一个模板类型,不管是unordered_set还是unordered_map,只要想要调用哈希表就需要把对应类型的模板参数传过来,所以这样我们就可以很好的解决Key模型和Key/Value模型使用同一份哈希代码的问题,具体代码如下:
在这里插入图片描述
如上图所示,总的来说,就是在使用unordered_set和unordered_map这两个模板类的时候,这两个模板类会去调用哈希表构造出一个对象,使用该对象去调用哈希表中的公共成员函数,并且此时传模板参数的时候,unordered_set传的是Key键,而unordered_map 传的是键值对pair结构体,并且注意:该pair结构中的数据也是模板类型,最后将模板参数传递给哈希表之后,哈希表在实例化的过程中,就会将对应的哈希结点给示例化成对应的数据类型,也就是你传Key,那么哈希结点就是Key类型,你传键值对,那么哈希结点就是键值对类型,这就是泛型编程的一大优点

2.解决泛型编程获取Key值问题
搞定了上述有关类型传参问题,此时我们正式开始封装,并且在红黑树中,我们对源码的写法已经有了教深的研究,此时我们就不再去看对应的源码了,因为本质都是换汤不换药,在红黑树封装set和map的博客中,我们已经将有关传模板参数导致不能确定类型的问题给解决了,也就是因为我们传的是模板参数,所以在编写红黑树代码的时候,不能使用具体的类型去访问数据,例:在进行比较大小的时候,unordered_set可以直接使用Key去比较大小,但是unordered_map却不行,因为unordered_map是一个键值对,是一个pair结构体,我们期望比较大小的方法是使用pair结构体中的Key去比较,而不是整个pair结构去比较,所以此时这个问题需要解决,解决的方法就是在unordered_set和unordered_map中构造一个内部类,该类实现一个仿函数,用于返回对应不同模型的Key值,最后再将该内部类作为一个模板参数传递到哈希表中,供给哈希表使用,哈希表再根据该模板参数取构造一个对象,使用该对象去调用对应的仿函数,最终利用仿函数获取到对应模型的Key值,如下代码所示:
在这里插入图片描述
如上图所示,通过上述文字和图示,应该可以很好的搞定该块知识点,本质就是想要获取到键值对pair结构体中的Key值而已,多了的没有,谁让我们想让unordered_set和unordered_map在一个桌子上吃饭呢?

3.解决存储数据类型的问题
OK,这个问题肯定是该篇博客的一个新知识点,虽然我们在哈希表实现的时候,已经详细的讲解过了,但是对于红黑树实现set和map来说,这个知识点是哈希表特有的,所以在此应该是属于新鲜货,值得我们重点讲解,同理哈希表中讲的,哈希表不是为了单单存储整形数据,而是希望可以存储任何类型的数据,无论是字符串类型还是自定义类型,所以为了解决这个问题,那么在进行哈希编码的时候,也就是使用哈希值进行哈希运算计算对应哈希地址的时候,我们需要将每种类型的数据都映射成一个整形数据,因为只有整形数据才可以符合哈希运算要求,但同理我们的数据类型使用的是模板类型,所以想要获取到这个数据类型映射出来的整形值,肯定不能在哈希表中获得,当然也不是在unordered_set或者unordered_map中获得,而是在我们调用unordered_set或者unordered_map进行传参时,通过一定的哈希函数实现获得,从而间接通过unordered_set和unordered_map
将该模板参数传递给哈希表,并且供给哈希表使用,让哈希表可以完成各种类型的哈希运算,从而在相应的哈希地址上存储各种类型的数据,如下图所示:
在这里插入图片描述

正式进入unordered_set和unordered_map的封装

搞定了上述有关泛型编程的知识,此时我们正式进入unordered_set和unordered_map的封装,本质没有什么太新奇的知识点,大致和set、map那块是类似的,也就是基础接口的封装和普通迭代器、const迭代器这些知识,并且基础接口的实现,就是去调用哈希表中对应的接口而已,所以不需要我们多讲,我们同样是把重点放在迭代器上,主要还是因为unordered_set的普通迭代器和const迭代器都是const迭代器,所以这块知识比较细化,需要我们琢磨一下

哈希表中迭代器相关知识

上篇博客,自我封装哈希表中,我们只实现了相关基础接口,并没有实现迭代器,所以因为此时unordered_set和unordered_map需要使用迭代器,此时我们就需要把哈希表的迭代器给实现,具体如下代码所示:
在这里插入图片描述
搞定了哈希表中有关迭代器的知识,此时我们就可以正式进入 unordered_set和 unordered_map的封装啦!如下:

unordered_set的封装

唯一值得注意的是,unordered_set的普通迭代器和const迭代器本质都是const迭代器,所以在实现迭代器时,一定需要格外小心,非常容易因为const导致出错,具体代码如下所示:
在这里插入图片描述

unordered_map的封装

同理,但不同的是此时unordered_map的普通迭代器就是普通迭代器,所以没什么需要特别注意的地方,如果有的话,那么就是键值对pair结构体中的Key值,我们要给成const类型,因为Key值坚决不允许被修改的,具体代码如下:
在这里插入图片描述

总结:哈希代码有关方面的知识,我们搞定的就差不多了,接下来只要认识一下哈希表在位图方面的应用,哈希表有关的知识我们就搞定啦!

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

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

相关文章

MySQL高级篇复盘笔记(二)【日志、主从复制、分库分表、读写分离】

❤ 作者主页:欢迎来到我的技术博客😎 ❀ 个人介绍:大家好,本人热衷于Java后端开发,欢迎来交流学习哦!( ̄▽ ̄)~* 🍊 如果文章对您有帮助,记得关注、点赞、收藏、…

【Redis25】Redis进阶:分布式锁实现

Redis进阶:分布式锁实现 锁这个概念,不知道大家掌握的怎么样。我是先通过 Java ,知道在编程语言中是如何使用锁的。一般 Java 的例子会是操作一个相同的文件,但其实我们知道,不管是文件,还是数据库中的一条…

Dapper存取Blob类型数据

🌮 Dapper存取Blob类型数据 前言: blob类型是数据库用于保存二进制文件的一种类型,可以将文件存储到数据库的表中。(使用到的情况比较少,毕竟文件可以直接在服务器上保存并且访问为什么要放到数据库里。但如果你服务器…

1.MySQL安装与配置

1.MySQL安装与配置 📤1 数据库介绍📤🚪1.1关于MySQL主要要学啥🚪 ✉️2 MySQL服务器安装✉️📄2.1 Windows绿色安装📄📑2.2 Windows中重装MySQL📑 📨3 Mac中常见的安装问…

多云环境中的微服务应用安全挑战

随着越来越多的组织将云策略扩展到私有云、公共云、本地数据中心和边缘站点,将多云作为数字转型倡议的一部分,新的安全挑战不断涌现,必须在安全倡议的每个阶段加以考虑。 在云中操作具有多个优势,任何组织,无论是公共…

在线答题小程序制作,这些坑你一定要避免

在线答题小程序制作,你需要知道以下几个关键点,才能避免一些常见的坑。这里,我会为你详细介绍如何制作一个高质量的在线答题小程序。 关键点一:确定目标用户群体 在制作在线答题小程序之前,你需要确定你的目标用户群…

行云创新受邀参加阿里云开发者技术沙龙,分享云原生技术实践案例

云原生IDE,定义开发新常态 2023年5月28日,由阿里举办的云原生技术实践营-阿里云开发者技术沙龙在深圳市南山区成功举办。本次沙龙活动主要围绕云原生话题开展实践案例经验分享,行云创新CEO马洪喜作为受邀嘉宾之一,参加了本次活动…

UITableView学习笔记

看TableView的资料其实已经蛮久了,一直想写点儿东西,却总是因为各种原因拖延,今天晚上有时间静下心来记录一些最近学习的TableView的知识。下面进入正题,UITableView堪称UIKit里面最复杂的一个控件了,使用起来不算难&a…

本地Linux搭建web服务并发布公网访问 - 无需公网IP

文章目录 前言1. 本地环境服务搭建2. 局域网测试访问3. 内网穿透3.1 ubuntu本地安装cpolar内网穿透3.2 创建隧道3.3 测试公网访问 4. 配置固定二级子域名4.1 保留一个二级子域名4.2 配置二级子域名4.3 测试访问公网固定二级子域名 转载自cpolar极点云的文章:在Ubunt…

代码随想录 栈与队列 Java

文章目录 (简单)232. 用栈实现队列(简单)225. 用队列实现栈(简单)20. 有效的括号(简单)1047. 删除字符串中的所有相邻重复项(中等)150. 逆波兰表达式求值&…

【红黑树 -- 理论与实现】

目录: 前言红黑树的概念红黑树的性质 插入过程遇到的情况情况1 -- 根节点情况2 -- parent为黑色情况3 -- parent为红色uncle为红色uncle为黑色uncle不存在 插入过程代码实现分析红黑树是否构建成功总结 前言 打怪升级:第88天 红黑树,可以说是…

Xubuntu16.04 系统偶发出现自动登出的问题

继上次发现的这个问题 xubuntu系统偶发自动登出,这次问题又浮现了,我第一时间拷贝了系统日志。 为了减少搜索量,可以先清除之前的系统日志,待问题出现 echo > /var/log/syslog echo > /var/log/kern.logMar 21 15:07:58 au…

面试:解决数字精度丢失

理论上用有限的空间来存储无限的小数是不可能保证精确的,但我们可以处理一下得到我们期望的结果 当你拿到 1.4000000000000001 这样的数据要展示时,建议使用 toPrecision 凑整并 parseFloat 转成数字后再显示,如下: parseFloat(…

为什么新产品没热度,流量分析

很多人反馈新产品上线之后却没有多少热度,这究竟是什么样原因呢?今天来为大家分享下为什么新产品没热度,流量分析。 新产品没有热度其实可以从两个主要方面进行探讨: 一、主观原因 1.缺乏吸引消费者的独特卖点 这个原因可能是新产品太过于普…

9个服务端提升debug效率的IDEA Debugger技巧

不可否认,未来的一到两年中,程序员的编码体验将会发生剧烈的变化。作为一名一线开发,要如何提前准备,来应对这种变化呢? 前言 在AIGC时代,虽然深度学习模型可以仅通过一段注释来生成我们想要的代码&#xf…

.net 混淆工具

obfuscation tools .net 社区有很多混淆工具, 比如这个清单: https://github.com/NotPrab/.NET-Obfuscator 比较有名的商业工具有 .NET REACTOR https://www.eziriz.com/, 开源软件中, 最受欢迎的有: obfuscar https://github.com/obfuscar/obfuscar老版 ConfuserEx https://gi…

代码危机!如何利用自定义异常应对复杂业务逻辑

大家好,我是小米,在这篇文章中,我将和大家分享关于自定义异常的使用场景以及一个实际的电商项目案例。自定义异常在软件开发中起到了重要的作用,能够帮助我们更好地管理和处理各种异常情况。让我们一起来看看各个场景下如何使用自…

85.建立主体页面-第一部分

记住我们之前画的草图&#xff0c;根据我们的草图来构建初始的页面 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta http-equiv"X-UA-Compatible" content"IEedge" /><meta n…

202313读书笔记|《山居七年》——我只想在广袤璀璨的星河里享受生的鲜活,独自飞,游走

202313读书笔记|《山居七年》——我只想在广袤璀璨的星河里享受生的鲜活&#xff0c;独自飞&#xff0c;游走 《山居七年》 作者张二冬&#xff0c;选择隐士山居是一种很自由随性的生活态度&#xff0c;我觉得这不是普通人可以拥有的&#xff0c;比如我&#xff0c;并未入世也…

Nginx学习1--介绍和安装

文章目录 官方网站常用功能核心组成下载安装源码安装linux包安装ubuntu安装docker安装 官方网站 http://nginx.org/ 官方文档 常用功能 静态资源部署处理静态文件、处理索引文件以及支持自动索引&#xff1b; Rewrite地址重写正则表达式 反向代理提供反向代理服务器&#xf…