当前位置: 首页 > article >正文

C++笔记-list

list即是我们之前学的链表,这篇主要还是讲解list的底层实现,前面会讲一些list区别于前面string和vector的一些接口以及它们的注意事项。

一.list的基本使用

和之前的string,vector一样,有很多之前见过的一些接口,经过前面两篇的讲解,很多接口不用讲解相信大家都会使用,主要就是Operations中的一些接口之前没有讲过,前面主要就是讲解这些接口。

这里主要讲splice,remove,unique和sort:

1.1splice:
splice的作用是将一个列表中的内容拷贝给另一个链表。

可以看出splice有三种传参的方式,每种方式都会产生不一样的结果:
1.1.1第一种传参

第一种传参中的两个参数:第一个参数就是从目标位置开始拷贝数据过去,第二个参数代表某个链表。

第一种传参方式就是把第二个参数中链表的所有数据都拷贝到第一个参数之前,结果如第二张图所示,lt1的所有数据都被拷贝到lt2的begin位置之前。

1.1.2第二种传参

第二种传参比第一种多了一个参数,意思就是把具体某个位置的值拷贝到目标位置之前,就比如上图所示的将lt1中的第一个数据拷贝过去。

1.1.3第三种传参方式

第三种传参就是把某个范围的数据拷贝过去,就比如上图中将lt1中的4到6拷贝过去。

这里可能会有人疑惑:为什么第三个参数直接写lt1.begin()+3呢?这样写不是更简洁吗?

这个问题我下面讲sort时会讲,这里先跳过。

splice还有一种玩法就是可以将自己的数据拷贝到某个位置之前,就比如将最后一个数据拷贝到第一个位置:

这样就将6放到了第一个位置,这种用法是要比前面的用法更为普遍的。

1.2remove

list中remove作用是将链表中所有和你要删除的值相同的数据一并删除。

如上图所示,这里就把所有的2都给删除了,remove的基本用法就是如此。

1.3unique

unique的作用就是删除一个有序链表中重复的数据。

通过unique就可以把重复的数据给删掉。

注意:一定要是有序的,如果不是有序的就无法做到删除重复的数据。

此时链表数据不是有序的,unique就没有发挥作用。

1.4sort

sort的作用相信就不用多说大家都知道,但是在这里我们要思考两个问题:

1.string和vector都没有实现sort接口,为什么list要单独实现?

2.list实现的sort效率怎么样?

先来解释第一个问题:
这个问题的答案也能解释上面splice出现的疑点,这就涉及到迭代器的分类。

迭代器分为三类(移动迭代方式):

1.单向迭代器,如:forword_list/unordered_map...   ++

2.双向迭代器,如:list/map...   ++/--

3.随机迭代器,如:string/vector/deque.. ++/--/+/-

后面就是它们能够进行的移动迭代方式,而语法库中的sort参数是随机迭代器,list都是双向迭代器,所以不能使用语法库中的sort,而上面的splice出现的疑点也是因为双向迭代器不能+/-,所以不能那样使用。

中间蓝色的单词的意思就是双向迭代器。

这是string和vector的随机迭代器。

这是语法库中的sort的参数要求,上去就要求随机迭代器,所以list才需要自己实现。

而迭代器的分类和之前讲的权限放大和缩小的概念有些类似,就是如果函数参数要求是双向迭代器,此时我们传随机迭代器也是可以的,相当于权限的缩小,同理单向迭代器也是如此。

双向迭代器和随机迭代器就是特殊的单向迭代器。

再来说第二个问题:
我就直接说结论,list自己实现的sort效率不高,比起语法库中的sort效率低了很多。

不过在数量较少时,效率差不多,但是在数量较大时效率就会低很多,举个例子:

在数量较大时,把list中的数据拷贝到vector,调用语法库中的sort,再把数据传回list的效率都比直接调用list本身的sort高。

二.list的底层实现

2.1list框架的实现

链表我们之前在数据结构阶段都了解过,链表要把整个链表和单个结点区分开,所以这里也是同理。

这里定义哨兵位,相信大家都知道底层list其实就是双向带头循环链表。

可能有人会疑惑:为什么单个结点要用struct而不用class?

其实我们在实际应用中,想让别人使用的用class,不想别人访问的用struct,我们只想让别人用链表整体,而不能直接访问我一个结点中的变量。

在单个结点类中运用初始化列表进行初始化,这样在list类中初始化哨兵位时就不需要传数据,直接创捷一个哨兵位,并让prev和next都指向自己即可,和之前讲链表是一样的。

2.2push_back尾插

思路和之前讲链表是一样的,创建一个节点,并更新哨兵位,原尾节点和新建结点的next和prev即可。

2.3iterator迭代器的实现

之前在string中讲过迭代器并不就一定是指针,在list中印证了。

为什么在list中要单独实现iterator迭代器呢?

因为在之前的string和vector中,它们两个底层都是数组,它们的原生指针就能完成解引用和++等操作,而链表我们知道解引用是访问一个结点,而一个结点不止有数据,还有prev和next,而迭代器我们要求解引用就是直接拿出其中的数据。

包括++等操作,链表底层并不是数组,每个结点的地址并不是连续的,所以通过++等操作是不能找到相邻的结点的。

基于以上两点,所以在list终究要我们自己实现iterator迭代器,而自定义类型的迭代器其实执行的还是指针的作用,所以成员变量依旧还是单个结点的地址。

其中里面所实现的各种比较我就不过多赘述了,之前都讲过,这里主要讲解一下为什么多加了一个类型Ref。

因为不仅有iterator,还有const_iterator,两者的区别无非就是解引用的值能不能修改的问题,但是如果我们没有多加Ref这个类型,那我们是不是还要写一个函数重载?

但是从之前学过的函数重载中我们知道,是不能以返回值不同而进行函数重载的,程序会报错,

那要解决这个问题就只能在单独写一个const_iterator类,内容和iterator一样,除了解引用符号的重载这一个不同而已。

这样写代码就太冗余了,有很多重复代码,但是我们加一个类型Ref就可以解决这个问题,根据传过去的参数不同将其分为iterator和const_iterator:

可能有人会疑惑:iterator类不需要实现析构函数吗?

我们所实现的iterator只是用于解引用和遍历链表而已,不能使用后直接把这个节点给销毁了,所以不能实现析构函数,相应的也不需要实现拷贝构造函数。

上面的结点类也是一样,析构操作只需要在list类中实现即可。

另外其中的!=,==等符号的重载是因为现在iterator是自定义类型,不再是原生指针,所以如果要比较自定义类型,就要重载相应的符号。

2.3begin和end

实现了迭代器iterator,接下来就要实现begin和end,也是分为普通和const版本,注意返回值是需要调用iterator类并进行传参的,头结点是哨兵位的下个结点,end返回就是哨兵位。

2.4insert

insert实现逻辑和之前一样,找到目标结点的prev和next,并更新三个结点的next和prev即可。

2.5erase

 

相信现在看到这个返回值大家就知道erase会出现什么问题了,没错,还是迭代器失效的问题,所以还是要在erase后更新指针。

需要注意的地方有两个:

1.目标结点不能是哨兵位

2.删除当前结点后,要更新指针的位置,指向下个结点

2.6push_front,pop_back和pop_front

这三个包括之前实现的push_back就都可以通过复用insert和erase来实现,要注意的就是尾删不能直接传end,要让end--才是尾结点的位置。

2.7clear

clear的作用就是销毁除哨兵位之外的所有结点,实现起来也较为容易,遍历整个链表挨个销毁即可。

2.7拷贝构造函数

实现拷贝构造函数也是为了深拷贝做准备,一样也要创建哨兵位,不过这和构造函数的代码一样,所以其实可以将这段代码封装成一个函数也可以,这里因为就几行代码所以我就没整。

下面就是遍历目标链表,把相应的节点push_back进去即可。

2.8=符号重载

以及是需要用到std标准库中的swap函数进行操作,最后=符号重载复用即可。

我们再看最后一种情况:

当传进去的参数类型是自定义类型时,我们要访问其中的数据要用到->符号,但是vector是可以直接用的,因为它用的是原生指针,而list不能使用,因为是自定义类型迭代器,所以在这里我们要自己实现->符号。

和上面的解引用重载一样,这里我们引进一种类型Ptr,代表要输出的数据的地址,所以也分为普通和const版本,作用也就和vector原生指针作用是一样的。

此时就不再会报错,但是可能有人会觉得很奇怪:不应该是两个箭头吗?

第一个箭头返回的是指针,应该还有一个箭头才能指向数据啊。

这个想法没错,出现这现象的原因是为了可读性高,编译器把另一个箭头给省略了。

以上就是list的内容。

 

相关文章:

C++笔记-list

list即是我们之前学的链表,这篇主要还是讲解list的底层实现,前面会讲一些list区别于前面string和vector的一些接口以及它们的注意事项。 一.list的基本使用 和之前的string,vector一样,有很多之前见过的一些接口,经过…...

k8s报错kubelet.go:2461] “Error getting node“ err=“node \“k8s-master\“ not found“

问题 首先最初问题: [rootk8s-master ~]# kubectl get pods -owide --all-namespaces The connection to the server 192.168.2.129:6443 was refused - did you specify the right host or port?检查kubelet状态 查看kubelet status报找不到master节点 [rootk8…...

open webui 介绍 是一个可扩展、功能丰富且用户友好的本地部署 AI 平台,支持完全离线运行。

AI MCP 系列 AgentGPT-01-入门介绍 Browser-use 是连接你的AI代理与浏览器的最简单方式 AI MCP(大模型上下文)-01-入门介绍 AI MCP(大模型上下文)-02-awesome-mcp-servers 精选的 MCP 服务器 AI MCP(大模型上下文)-03-open webui 介绍 是一个可扩展、功能丰富且用户友好的…...

使用cursor进行原型图设计

1.下载cursor 2.模式设置: 模型使用claude-3.7-sonnet的think模式 3.引导词模板: 我想要开发一个中高考英语口语考试的模拟考试系统,我需要将上面的这个应用输出成高保真的原型图设计。请考虑以下的规范: 用户体验&#xff1…...

极狐GitLab 登录限制如何设置?

极狐GitLab 是 GitLab 在中国的发行版,关于中文参考文档和资料有: 极狐GitLab 中文文档极狐GitLab 中文论坛极狐GitLab 官网 登录限制 (BASIC SELF) 您可以使用登录限制自定义 Web 界面以及基于 HTTP(S) 的 Git 的身份验证限制。 设置 要访问登录限…...

设计模式之工厂模式(factory pattern):在商品对象创建系统中的应用

目录 一、设计思路 1. 简单工厂模式 2. 工厂方法模式 3. 抽象工厂模式 二、UML类图(PlantUML格式) 1.简单工厂模式 2.工厂方法模式 3.抽象工厂模式 三、实现过程与结果 1. 简单工厂模式 2. 工厂方法模式 3. 抽象工厂模式 四、总结 在面向对…...

Spring Boot 自定义定时任务组件深度解析:Quartz 集成与设计模式实战

一、组件设计目标 解决痛点: 简化 Quartz 原生 API 的复杂性统一任务调度管理(增删改查、日志、重试)与 Spring Boot 生态无缝整合 二、实现步骤详解 1. 组件初始化配置 1.1 初始化 Quartz 表结构 下载 SQL 脚本 🔗 官方表…...

嵌入式exfat-nofuse文件系统移植和使用

exfat-nofuse 是一款专为linux ARM平台设计的开源项目,它提供了一个非FUSE机制的内核级驱动,用于在Linux系统上无缝地读写exFAT和VFAT文件系统。此项目由Dorimanx维护,采用C语言编写,兼容GPL-2.0许可证。它避开了FUSE(用户空间文件系统)的使用…...

再来一篇,Linux中的软件管理

Linux中软件包的类型 在Linux系统中,软件包有多种不同的格式和类型,主要包括以下几种: DEB (Debian软件包)(此软件包不适用于RHEL8 系统): 适用于 Debian 及其衍生版本(如Ubuntu等&…...

【重学Android】02.Java环境配置的一些分享

背景说明 其实只是学习Android的话,只要下载好Android Studio开发工具,是自带JDK环境的,所以不需要再额外去进行配置,我之所以还要进行单独配置,是因为我其他的工具需要Java的环境,而且我目前用的是JDK 12…...

SimBody安装

SimBody安装 Simbody 是一个用于创建生物力学和机械系统仿真的多体动力学库。 SimBody安装 Windows安装: 下载地址:GitHub - simbody/simbody: High-performance C multibody dynamics/physics library for simulating articulated biomechanical and…...

CUDA编程中影响性能的小细节总结

一、内存访问优化 合并内存访问:确保相邻线程访问连续内存地址(全局内存对齐访问)。优先使用共享内存(Shared Memory)减少全局内存访问。避免共享内存的Bank Conflict(例如,使用padding或调整访…...

thinkphp:部署完整项目到本地phpstudy

一、准备工作 首先准备一个thinkphp的项目文件;准备mysql数据库 二、小皮初步搭建 1、建立网站 在小皮界面,网站->创建网站->输入域名,选择PHP版本等 注:确保端口未被占用 2、将项目文件放入根目录 网站->管理->…...

Linux网络编程——基于ET模式下的Reactor

一、前言 上篇文章中我们已经讲解了多路转接剩下的两个接口:poll和epoll,并且知道了epoll的两种工作模式分别是 LT模式和ET模式,下来我们就实现的是一个简洁版的 Reactor,即半同步半异步I/O,在linux网络中&#xff0c…...

大模型相关面试问题原理及举例

大模型相关面试问题原理及举例 目录 大模型相关面试问题原理及举例Transformer相关面试问题原理及举例大模型模型结构相关面试问题原理及举例注意力机制相关面试问题原理及举例大模型与传统模型区别 原理:大模型靠海量参数和复杂结构,能学习更复杂模式。传统模型参数少、结构…...

Redis List 的详细介绍

Redis List 的详细介绍 以下是 Redis List 的详细介绍,从基础命令、内部编码和使用场景三个维度展开: 一、基础命令 Redis List 支持双向操作(头尾插入/删除),适用于队列、栈等场景,以下是核心命令分类&a…...

使用virtualbox的HostOnly建立共享网络-实现虚拟机上网

目录 环境描述解决方案具体步骤1.新建一个virtual host-only ethernet adapter2.设置windows的wifi信号网络共享3.确认winows宿主网络信息3.1.wifi适配器的信息3.2.虚拟网卡的信息3.3.确认virtualbox中虚拟网卡的ip地址 4.虚拟机网卡设置5.虚拟机网络设置5.1.本地连接设置5.2.u…...

springboot+vue3+mysql+websocket实现的即时通讯软件

项目演示 即时通讯软件项目演示 业务架构 技术栈 后端 选用编程语言 Javaweb框架SpringBootdb MySQL 持久存储nosql 缓存 Redis全双工通信框架 WebSocket 前端 前端框架Vue3TypescriptUI样式 Css、ElementPlus网页路由 vue-router全双工通信框架Websocket 功能完成情况 已实…...

基于 Spring Boot 瑞吉外卖系统开发(五)

基于 Spring Boot 瑞吉外卖系统开发(五) 删除分类 分类列表中每条分类信息右侧提供了一个“删除”按钮,当需要将已经存在的分类信息删除时,可以通过单击“删除”按钮实现。 请求路径为/category,携带参数id&#xf…...

AES (高级加密标准)

原理详解 AES是一种对称加密算法,使用相同的密钥进行加密和解密。它采用替代-置换网络(SPN)结构,主要步骤包括: 密钥扩展:从初始密钥派生多轮密钥 初始轮:AddRoundKey(轮密钥加) 主轮&#xff…...

详解Windows(一)——系统盘下目录及文件详解

引言 你是否曾经好奇过电脑里那些神秘的文件夹都是干什么用的?为什么有些文件是.exe而有些是.dll?不同的图片格式.jpg和.png到底有什么区别?如果你对这些问题感到困惑,这篇文章就是为你准备的。今天,我们将以通俗易懂…...

基于Spring MVC的客户端真实IP获取方案解析

文章目录 基于Spring MVC的客户端真实IP获取方案解析概述核心方法解析代码实现工作流程 IP获取优先级策略IP有效性验证异常处理与日志使用场景注意事项扩展建议 基于Spring MVC的客户端真实IP获取方案解析 概述 在Web应用开发中,准确获取客户端真实IP地址是常见的…...

【Web部署问题】在Tomcat中部署web项目出现http状态-404 -未找到详细解决方案

部署完tomcat记得在选中要运行的工件。 如果没有工件,或者工件有缺失东西,去这里配置工件,...

Linux——Shell编程之正则表达式与文本处理器(笔记)

目录 基础正则表达式 1:基础正则表达式示例 (4)查找任意一个字符“.”与重新字符“*” (5)查找连续字符范围“{ }” 文本处理器 一、sed工具 二、awk工具 (1)按行输出文本 (2&#xff0…...

Linux 进程控制(自用)

非阻塞调用waitpid 这样父进程就不会阻塞,此时循环使用我们可以让父进程执行其他任务而不是阻塞等待 进程程序替换 进程PCB加载到内存中的代码和数据 替换就是完全替换当前进程的代码段、数据段、堆和栈,保存当前的PCB 代码指的是二进制代码不是源码&a…...

05-DevOps-Jenkins自动拉取构建代码

新建Gitlab仓库 先在Gitab上创建一个代码仓库,选择创建空白项目 安装说明进行填写,然后点击创建项目 创建好的仓库是空的,什么都没有 新建一个springboot项目,用于代码上传使用。 只是为了测试代码上传功能,所以代码…...

【Spring学习】

Spring学习 简介 Spring 是一个开源的 Java 企业级开发框架,最核心的特点是: IOC(控制反转)AOP(面向切面编程) 它有完整的生态: 🚀 Spring Boot:用于快速构建服务&a…...

网络基础与 HTTP 协议

一、网络基础 (一)TCP/IP 协议族 TCP/IP 协议族是互联网通信的核心协议,它包含了多个层次的协议,共同协作实现网络通信。 1. IP 协议 IP(Internet Protocol)协议位于网络层,主要负责将数据包…...

SRS transcode支持 h264_nvenc 硬件解码方案

文章目录 SRS transcode支持 h264_nvenc 硬件解码方案1、修改文件2、重新编译3、使用 SRS transcode支持 h264_nvenc 硬件解码方案 SRS 是开源的流媒体服务,但在使用 GPU 服务器时,想要通过硬件加速,目前官方是不支持的,所以简单…...

阿里云服务器搭建开源版禅道

一,下载地址:禅道11.5版本发布,主要完善细节,修复bug,新增动态过滤机制 - 禅道下载 - 禅道项目管理软件 下载地址二: 禅道21.6.stable 实现旧编辑器撰写的文档无感升级至新版编辑器 - 禅道下载 - 禅道项目…...