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

C++基础语法:STL之容器(4)--序列容器中的list(一)

前言

       "打牢基础,万事不愁" .C++的基础语法的学习

引入


        序列容器的学习.以<C++ Prime Plus> 6th Edition(以下称"本书")内容理解

        本书中容器内容不多只有几页.最好是有数据结构方面的知识积累,如果没有在学的同时补上.

        序列容器回顾:序列容器内元素按严格线性顺序排列,至少是正向迭代器(含以上).序列容器包括deque(双端队列),forward_list(单链表),list(双向链表),queue(队列),priority_queue(优先队列),stack(栈),vector(动态数组),array(替代数组的容器

list(双向链表) 

        list所占篇幅相对其他容器类算比较大的,而且有专属的api介绍.

        list双向链表,和单链表比较起来,在结点上多了个指向前面一个元素的指针.

        本书内容解读 

        第1部分:  list模板类(在list头文件中声明)表示双向链表。除了第一个和最后一个元素外,每个元素都与前后的元素相链接,这意味着可以双向遍历链表。list和vector之间关键的区别在于,list在链表中任一位置进行插入和删除的时间都是固定的(vector模板提供了除结尾处外的线性时间的插入和删除,在结尾处,它提供了固定时间的插入和删除)。因此,vector强调的是通过随机访问进行快速访问,而list强调的是元素的快速插入和删除 (本书原话)

         ----蓝色部分是list应用场景,切记

         ----代码和解读:

        注意:下列代码为了练手,试图重现逻辑,不保证准确.          

template<class T>
class list{enum{MAX=10}int lsize;                //list最大元素数量int items;                //list内当前的元素个数class Node{               //声明结点类public:                   //结点数据向外部类公开T t;Node *front;Node *next;Node(T val):t(val),front(0),next(0){}Node(){}              //默认构造函数,为初始化时使用}Node* first;Node* last;
public:list(int num=MAX);        //构造函数   void add(Node* n,T& t);   //添加元素t到结点n后面T remove(Node* n);        //删除地址为n的结点
}

        1>构造函数,建立初始的list

        说明:first按照"头结点"定义,数据域为空的结点,初始化时没有元素,所以last也指向头结点.

template<class T>
list::list(int num=MAX):lsize(num){ //初始化list,没有元素时的情况items=0;                        //初始时元素个数为0Node *newNode=new Node;         //创建数据域为空的结点first=newNode;                  //头结点指向空结点;last=newNode;                   //末结点指向空结点;//  last->next=first;               //如果加上这句,末结点后面的结点指向头结点,形成环状list//这里不加,仍然是一根链条似的list,加了变复杂用处也不大,不加
}

        2>添加元素

        把结点地址作为参数,作为插入元素的条件,向序列要求函数中的迭代器靠拢.

template<class T>
void list<T>::add(Node* n,T& t){Node* newNode=new Node(t);    //生成新结点,传入数据
/*新结点后面是谁*/newNode->next=n->next;n->next->front=newNode;
/*新结点在谁后面*/n->next=newNode;newNode->front=n;
/*第一次插入后,新结点成为尾结点,并在头结点后面*/if(items==0){                //第一次插入时情况:区分first和lastnewNode->next=nullptr;   //新结点后面指空last=newNode;            //新结点成了尾结点first->next=newNode;     //first当上了头结点newNode->front=first;    //两个方向说明first当上了头结点}            
//  if(n==first)
//      first->next=newNode;     //插入在头结点之后,前面代码已符合不用重复if(n==last)                 last=newNode;            //如果在末尾插入,尾结点指向新结点仍是尾结点items++;                     //list元素个数加1
}

        3>删除某个位置的结点 

template<class T>
T list<T>::remove(Node* n){Node* tmp=n;                //标识要删除的结点/*把要删除的结点从list里面剥离出来*/n->next->front=n->front;    //该结点后面结点的front指向该结点前面那个结点n->front->next=n->next;     //该结点前面那个结点的next指向该结点后面if(n==last)                 //如果删除的是尾结点last=n->front;         //尾结点指向删除结点的前一个结点T t=tmp->t;                 //标识结点的数据取出来delete tmp;                 //删除标识结点items--;                    //删除结点,元素个数减1return t;                   //返回原结点内数据
}        

================================内容分割线=================================

做几个小分析:

        1.构造函数用了两个,如果只有下面这个,建立空结点不知道能不能成功,笔者未尝试.

          在C语言中,声明一个结构体并且malloc,好像不用给数据也没错,C++的检查更严格.

Node(T val):t(val),front(0),next(0){}

        2.关于环状list

          如果采用"环状"list,那么后面的代码中last不能指空,而要指向first.其他算法可能会有区别

           在插入,删除或者查找中,环状list未必能达到好的效果.考虑到一种场景:list很长,查询数据时查一半不找了,往回查找走,这时考虑用环状list.如图:

     有兴趣可以尝试做个环状list,再写个查找算法.

     不过数据多了有更好的选择,比如二叉树等,所以感觉实用性不大.

        3. 头结点  

        头结点实际上是"人造"的.他的用途是方便元素在头部插入和删除.是否选择用头结点在于程序员.如果不做头结点,让头部插入的结点成为首个结点,那么代码要做一些修改,代码要多一点.

        4.第一次插入时的描述

        以下是函数add里的部分代码:

/*第一次插入后,新结点成为尾结点,并在头结点后面*/if(items==0){                //第一次插入时情况:区分first和lastnewNode->next=nullptr;   //新结点后面指空last=newNode;            //新结点成了尾结点first->next=newNode;     //first当上了头结点newNode->front=first;    //两个方向说明first当上了头结点}

        参照本书P614,链队列的"入队"算法enque,开始时first和last都指向同一个空结点,将第一次插入和其他次插入分开,才可以在逻辑上区分first和last,保证后面的程序正确. 

        5.程序中的"一般"和"特别"

        add中的部分代码 

//  if(n==first)
//      first->next=newNode;     //插入在头结点之后,前面代码已符合不用重复if(n==last)                 last=newNode;            //如果在末尾插入,尾结点指向新结点仍是尾结点

        当写完add后,如果想在头结点后插入元素,代入first,发现逻辑仍成立,所以注释部分属于多余描述;而当在末尾结点插入元素,代入last,函数执行完毕后发现尾结点位置没变,所以给了if做补充. 

        函数代入的形参可以被看作是所有可能的组合 ,表示"一般"性.当一般性不能满足所有情况,需要用"特殊"的描述做补充,这也是程序调试的重要性所在.

        6.尾结点last为什么有时候需要有时候不需要?

        对比以前的数据结构单链表C++基础语法:链表和数据结构-CSDN博客和链队列,他们一个没有尾结点,一个有尾结点,list也有尾结点.而链队列和list的共同特征是需要在"尾部"插入和删除元素,因此定义了尾结点last并实现了他.而使用"头插法"的单链表既没有"尾部"的概念,也没有"尾结点"存在.与此相对应的,头结点(指向首个元素的结点)是必须存在的,因为靠他遍历到容器内所有数据.

        同时定义了list的最大元素个数items,但并没有使用他,所以本例的链表可以无限长 

        结论:容器里的属性是根据需要定义并实现的

        7.迭代器

        此前迭代器让人挠头,迭代器类里的属性复刻了容器里的数据(因为容器里都是数据集合,所以属性是容器集合的指针),所以迭代器实际上是对数据的二重访问和修改.提升了"同一性"(每个容器里都有个迭代器类).在容器类里对元素的增删改搬到迭代器里去了,然后做接口被容器类对象访问.

        迭代器做参数,先转化成对应的指针即可.本例的指针做参数和迭代器做参数已非常接近 

        8.函数的"冗余"

        在序列函数中,有push_front()函数,为了在容器头部插入数据,有了add()函数也一样可以实现.为什么要这样做呢?

        原因和"迭代器"一样,他是为了同属于序列容器"同一性"提供的api,而且也容易实现,把参数传给add()就行了. 

================================内容分割线================================ 

         第2部分:与vector相似,list也是可反转容器。与vector不同的是,list不支持数组表示法和随机访问。与矢量迭代器不同,从容器中插入或删除元素之后,链表迭代器指向元素将不变。我们来解释一下这句话。例如,假设有一个指向vector容器第5个元素的迭代器,并在容器的起始处插入一 个元素。此时,必须移动其他所有元素,以便腾出位置,因此插入后,第5个元素包含的值将是以前第4个元素的值。因此,迭代器指向的位置不变,但数据不同。然后,在链表中插入新元素并不会移动已有的元素,而只是修改链接信息。指向某个元素的迭代器仍然指向该元素,但它链接的元素可能与以前不同。

        ----解读:这段比较容易理解:如果支持随机访问,那么两次访问到的数据不能改变.而list(包括其他链表)在插入和删除后,原数据的位置发生改变,再次用位置访问到的数据和之前不一样了,所以不能随机查找,而只能通过遍历来搜寻.

小结

        list双向链表的一些理解.

相关文章:

C++基础语法:STL之容器(4)--序列容器中的list(一)

前言 "打牢基础,万事不愁" .C的基础语法的学习 引入 序列容器的学习.以<C Prime Plus> 6th Edition(以下称"本书")内容理解 本书中容器内容不多只有几页.最好是有数据结构方面的知识积累,如果没有在学的同时补上. 序列容器回顾:序列容器内元素按严格…...

WordPress杂技

WordPress杂技 WordPress页面构建器: Avada、Elementor、astra、 Elementor作为一款强大的页面构建工具。 Avada&#xff1a;是一款非常受欢迎的WordPress主题&#xff0c;它的设计理念是简洁、现代、响应式&#xff0c;Avada拥有丰富的模板和布局&#xff0c;可以轻松创建出…...

鸿蒙 动态共享包HSP的创建和引用

1.什么是动态共享包HSP HSP&#xff08;Harmony Shared Package&#xff09;是动态共享包&#xff0c;可以包含代码、C库、资源和配置文件&#xff0c;通过HSP可以实现代码和资源的共享。HSP不支持独立发布&#xff0c;而是跟随其宿主应用的APP包一起发布&#xff0c;与宿主应…...

ARM架构(二)—— arm v7-a/v8/v9寄存器介绍

1、ARM v7-A寄存器 1.1 通用寄存器 V7 V8开始 FIQ个IRQ优先级一样&#xff0c; 通用寄存器&#xff1a;31个 1.2 程序状态寄存器 CPSR是程序状态毒存器&#xff0c;保存条件标志位&#xff0c;中断禁止位&#xff0c;当前处理器模式等控制和状态位。每种异常模式下还存在SPS…...

C++合作开发项目:美术馆1.0

快乐星空MakerZINCFFO 合作入口&#xff1a;CM工作室 效果图&#xff1a; 代码&#xff1a; &#xff08;还有几个音乐&#xff01;&#xff09; main.cpp #include <bits/stdc.h> #include <windows.h> #include <conio.h> #include <time.h> #in…...

QT 5 同时使用Q_DECLARE_METATYPE(pointdata) 和继承 QObjectUserData

在Qt框架中&#xff0c;QObjectUserData 和 Q_DECLARE_METATYPE() 宏都与Qt的元对象系统有关&#xff0c;但它们的使用方式有一些特别的限制和兼容性问题。 关于QObjectUserData&#xff1a; QObjectUserData 是一个用来存储用户数据的类。在Qt中&#xff0c;每个 QObject 可以…...

【MySQL进阶之路 | 高级篇】范式概述与第一范式

1. 范式简介 在关系型数据库中&#xff0c;关于数据表的设计的基本原则&#xff0c;规则就称为范式。可以理解为&#xff0c;一张数据表的设计结果需要满足的某种设计标准的级别。要想设计一个结构合理的关系型数据库&#xff0c;必须满足一定的范式。 范式的英文名是Normal …...

Open-TeleVision复现及机器人迁移

相关信息 标题 Open-TeleVision: Teleoperation with Immersive Active Visual Feedback作者 Xuxin Cheng1 Jialong Li1 Shiqi Yang1 Ge Yang2 Xiaolong Wang1 UC San Diego1 MIT2主页 https://robot-tv.github.io/链接 https://robot-tv.github.io/resources/television.pdf代…...

Notepad++换安装路径之后,右键打开方式报错:Windows无法访问指定设备、路径或文件。你可能没有适当的权限访问该项目。的处理方法

把Notepad添加到右键打开方式&#xff0c;可以参考下面的3篇文章添加&#xff1a; https://blog.csdn.net/xiaoerbuyu1233/article/details/88287747 https://blog.csdn.net/qq_44000337/article/details/120277317 https://www.cnblogs.com/zhrngM/p/12899026.html 这里主要是…...

【Flutter 面试题】 使用成熟状态管理库的弊端有哪些?

【Flutter 面试题】 使用成熟状态管理库的弊端有哪些? 文章目录 写在前面口述回答补充说明写在前面 🙋 关于我 ,小雨青年 👉 CSDN博客专家,GitChat专栏作者,阿里云社区专家博主,51CTO专家博主。2023博客之星TOP153。 👏🏻 正在学 Flutter 的同学,你好! 😊 …...

Apache Commons技术详解

文章目录 简介官网链接原理基础使用Commons LangCommons Collections 高级使用Commons IOCommons Math 优缺点优点缺点 总结 简介 Apache Commons 是 Apache 软件基金会下的一个项目&#xff0c;旨在提供可重用的Java组件。这些组件覆盖了广泛的编程任务&#xff0c;从字符串处…...

怎样使用 Juicer tools 的 dump 命令将.hic文件转换为交互矩阵matrix计数文件 (Windows)

创作日志&#xff1a; 万恶的生信…一个scHiC数据集没有提供处理好的计数文件&#xff0c;需要从.hic转换。Github一个个好长的文档看了好久才定位到 juicer tools 的dump命令&#xff0c;使用起来比想象中简单。 一、下载Juicer tools 注意&#xff1a;使用Juicer tools的前提…...

【Docker】Docker Desktop - WSL update failed

问题描述 Windows上安装完成docker desktop之后&#xff0c;第一次启动失败&#xff0c;提示&#xff1a;WSL update failed 解决方案 打开Windows PowerShell 手动执行&#xff1a; wsl --set-default-version 2 wsl --update...

基于rsync\unlink 等一套本机备份跨机备份历史备份清理shell 脚本

一 摘要 本文主要介绍一套本地备份、跨机器备份、历史备份清理脚本&#xff0c;使用场景如数据库备份等 二 环境 linux 系列系统 基本都支持&#xff0c;个别命令可能需要微调。 2.1 实验环境 [rootlocalhost rsync]# cat /etc/centos-release CentOS Linux release 7.9.2…...

使用nginx实现一个端口和ip访问多个vue前端

前言&#xff1a;由于安全组要求&#xff0c;前端页面只开放一个端口&#xff0c;但是项目有多个前端&#xff0c;此前一直使用的是一个前端使用单独一个端口进行访问&#xff0c;现在需要调整。 需要实现&#xff1a;这里以80端口为例&#xff0c;两个前端分别是&#xff1a;p…...

Linux云计算 |【第一阶段】SERVICES-DAY5

主要内容&#xff1a; 源码编译安装、rsync同步操作、inotify实时同步、数据库服务基础 实操前骤&#xff1a;&#xff08;所需tools.tar.gz与users.sql&#xff09; 1.两台主机设置SELinnx和关闭防火墙 setenforce 0 systemctl stop firewalld.service //停止防火墙 sy…...

IP第一次综合实验

一、实验拓扑 二、实验要求 1、R6为ISP&#xff0c;接口IP地址均为公有地址&#xff0c;该设备只能配置地址之后不能冉对其进行任何配置 2、R1-R5为局域网&#xff0c;私有Ip地址192.168.1.0/24&#xff0c;请合理分配 3、R1、82、R4&#xff0c;各有两个环回IP地址;R5,R6各…...

Could not load dynamic library ‘cudart64_100.dll‘

python代码报错 Could not load dynamic library cudart64_100.dll; dlerror: cudart64_100.dll not found 2024-07-22 14:19:21.931639: I tensorflow/stream_executor/cuda/cudart_stub.cc:29] Ignore above cudart dlerror if you do not have a GPU set up on your machine…...

四大引用——强软弱虚

目录 一、强引用 二、软引用 三、弱引用 四、虚引用 一、强引用 强引用是在程序代码之中普遍存在的&#xff0c;类似于“Object obj new Object()”&#xff0c;obj变量引用Object这个对象&#xff0c;就叫做强引用。当内存空间不足&#xff0c;Java虚拟机宁愿抛出OutOfMe…...

MySQL--索引(2)

InnoDB 1.索引类型 主键索引(Primary Key) 数据表的主键列使用的就是主键索引。 一张数据表有只能有一个主键&#xff0c;并且主键不能为 null&#xff0c;不能重复。 在 mysql 的 InnoDB 的表中&#xff0c;当没有显示的指定表的主键时&#xff0c;InnoDB 会自动先检查表中是…...

java_网络服务相关_gateway_nacos_feign区别联系

1. spring-cloud-starter-gateway 作用&#xff1a;作为微服务架构的网关&#xff0c;统一入口&#xff0c;处理所有外部请求。 核心能力&#xff1a; 路由转发&#xff08;基于路径、服务名等&#xff09;过滤器&#xff08;鉴权、限流、日志、Header 处理&#xff09;支持负…...

关于nvm与node.js

1 安装nvm 安装过程中手动修改 nvm的安装路径&#xff0c; 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解&#xff0c;但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后&#xff0c;通常在该文件中会出现以下配置&…...

渲染学进阶内容——模型

最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...

【项目实战】通过多模态+LangGraph实现PPT生成助手

PPT自动生成系统 基于LangGraph的PPT自动生成系统&#xff0c;可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析&#xff1a;自动解析Markdown文档结构PPT模板分析&#xff1a;分析PPT模板的布局和风格智能布局决策&#xff1a;匹配内容与合适的PPT布局自动…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放

简介 前面两期文章我们介绍了I2S的读取和写入&#xff0c;一个是通过INMP441麦克风模块采集音频&#xff0c;一个是通过PCM5102A模块播放音频&#xff0c;那如果我们将两者结合起来&#xff0c;将麦克风采集到的音频通过PCM5102A播放&#xff0c;是不是就可以做一个扩音器了呢…...

相机从app启动流程

一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

【配置 YOLOX 用于按目录分类的图片数据集】

现在的图标点选越来越多&#xff0c;如何一步解决&#xff0c;采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集&#xff08;每个目录代表一个类别&#xff0c;目录下是该类别的所有图片&#xff09;&#xff0c;你需要进行以下配置步骤&#x…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

stm32wle5 lpuart DMA数据不接收

配置波特率9600时&#xff0c;需要使用外部低速晶振...

数据库——redis

一、Redis 介绍 1. 概述 Redis&#xff08;Remote Dictionary Server&#xff09;是一个开源的、高性能的内存键值数据库系统&#xff0c;具有以下核心特点&#xff1a; 内存存储架构&#xff1a;数据主要存储在内存中&#xff0c;提供微秒级的读写响应 多数据结构支持&…...