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

【c++_containers】10分钟带你学会list

前言

        链表作为一个像是用“链子”链接起来的容器,在数据的存储等方面极为便捷。虽然单链表单独在实际的应用中没用什么作用,但是当他可以结合其他结构,比如哈希桶之类的。不过今天学习的list其实是一个带头双向链表。

言归正传,让我们看一下list的特性。

一、list的特性

这里我还是推荐去cplusplus上阅读英文原文档。这里我总结了几条,

1. list 是可以在常数范围内 在任意位置进行插入和删除的序列式容器 ,并且该容器 可以前后双向迭代。
2. list 的底层是 双向链表结构 ,双向链表中每个 元素存储在互不相关的独立节点 中,在节点中通过指针指向其前一个元素和后一个元素。
3. list forward_list 非常相似:最主要的不同在于 forward_list是单链表 ,只能朝前迭代,已让其更简单高效。
4. 与其他的序列式容器相比 (array vector deque) list 通常 在任意位置进行插入、移除元素的执行效率更好。
5. 与其他序列式容器相比, list forward_list 最大的缺陷是 不支持任意位置的随机访问 ,比如:要访问 list的第6 个元素,必须从已知的位置 ( 比如头部或者尾部 ) 迭代到该位置,在这段位置上迭代需要线性的时间开销;list 还需要一些 额外的空间, 以保存每个节点的相关联信息 ( 对于存储类型较小元素的大 list 来说这可能是一个重要的因素)。

其物理模型简化后如下图:

二、list的基本结构

前面我们提到list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。那么他每个小结点的结构就变得清楚明了了。

    template<class T>struct list_node{list_node<T>* _prev;list_node<T>* _next;T _val;list_node(const T& val = T()): _prev(nullptr), _next(nullptr), _val(val){}			};

随后我们就可以写list的本体了

    template<class T>class list{typedef list_node<T> Node;private:Node* _head;//哨兵位size_t _size;};

加一个表示size的数据是因为list的空间是不连续的。

三、list的基础构造

        void empty_init(){_head = new Node;_head->_prev = _head;_head->_next = _head;_size = 0;}list(){empty_init();}

将empty经行再封装是因为这样的构造函数设计可以方便地创建空的list对象,并且避免了在创建list对象时必须显式地指定初始大小。同时,通过将初始化代码封装在empty_init()函数中,可以简化list类的实现,提高代码的可读性和可维护性。

四、list的插入与删除

与vector不同的是list的其他几种构造或多或少的依赖插入,而且哨兵位的初始化就可以继续后面的操作。当然插入和删除是list的重要点。

我们先从尾插写起,如图当插入一个节点时我们可以先新建一个新的节点,将值存入其中。然后将末尾(_head->_prev)的_next与newnode链接,然后将new的_prev与末尾链接,最后将头节点的_prev指向newnode,newnode的_next与_head链接。

        void push_back(const T&x){Node* newnode = new Node(x);Node* tail = _head->_prev;tail->_next = newnode;newnode->_prev = tail;newnode->_next = _head;_head->_prev = newnode;_size++;}

而对于任意位置插入,其实和上面的逻辑相似。

        //在pos之前插入,返回新插入元素位置iterator insert(iterator pos, const T& x){Node* cur = pos._node;Node* prev = cur->_prev;Node* newnode = new Node(x);prev->_next = newnode;newnode->_next = cur;cur->_prev = newnode;newnode->_prev = prev;++_size;return newnode;}

与次对立的是list任意位置的删除。逻辑就是他反过来。

        iterator erase(iterator pos){assert(pos != end());Node* cur = pos._node;Node* prev = cur->_prev;Node* next = cur->_next;prev->_next = next;next->_prev = prev;delete cur;--_size;return next;}

但是list的删除面临着迭代器的失效前面说过,此处大家可将迭代器暂时理解成类似于指针,迭代器失效即迭代器所指向的节点的无效,即该节 点被删除了。因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响

比如下面的案例:

void TestListIterator1()
{int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };list<int> l(array, array+sizeof(array)/sizeof(array[0]));auto it = l.begin();while (it != l.end()){l.erase(it); ++it;}// erase()函数执行后,it所指向的节点已被删除,因此it无效,在下一次使用it时,必须先给
其赋值改正后:
void TestListIterator()
{int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };list<int> l(array, array+sizeof(array)/sizeof(array[0]));auto it = l.begin();while (it != l.end()){l.erase(it++); // it = l.erase(it);}
}

当这两个比较泛型的插入与删除实现后其余代码就变得简单了。

//拷贝构造        list(const list<T>& lt)//list(const list& lt){empty_init();for (auto& e : lt){push_back(e);}}
//析构函数~list(){clear();delete _head;_head = nullptr;}
//头插void push_front(const T& x){insert(begin(), x);}
//尾删void pop_back(){erase(--end());}
//头删void pop_front(){erase(begin());}
//清空void clear(){iterator it = begin();while (it != end()){it = erase(it);}_size = 0;}

五、list的迭代器

list的迭代器我们要实现的主要就是他的++与--问题,而++就是返回当前位置的_next, --就是返回当前位置的_prev。

template<class T,class Ref,class Ptr>struct _list_iterator{typedef list_node<T> Node;typedef _list_iterator<T, Ref,Ptr> self;Node* _node;_list_iterator(Node* node):_node(node){}Ref& operator*(){return _node->_val;}Ptr operator->(){return &_node->_val;}self& operator++() {_node = _node->_next;return *this;}self& operator++(int)//后置{self tmp(*this);_node = _node->_next;return tmp;}self& operator--(){_node = _node->_prev;return *this;}self operator--(int){self tmp(*this);_node = _node->_prev;return tmp;}bool operator!=(const self & it)const{return _node != it._node;}bool operator==(const self & it)const{return _node == it._node;}};

_list_iterator类模板的三个类型参数分别为T(元素类型)、Ref(引用类型)和Ptr(指针类型)。这个类包含一个成员变量_node,它是一个指向list_node对象的指针,用于存储当前迭代器所指向的节点。这里的Ref与Ptr主要用于分辨const与非const.

六、list与vector的对比

vector
list
动态顺序表,一段连续空间
带头结点的双向循环链表
访
支持随机访问,访问某个元素效率 O(1)
不支持随机访问,访问某个元素 效率 O(N)
任意位置插入和删除效率低,需要搬移元素,时间复杂 度为 O(N) ,插入时有可能需要增容,增容:开辟新空 间,拷贝元素,释放旧空间,导致效率更低
任意位置插入和删除效率高,不
需要搬移元素,时间复杂度为 O(1)
底层为连续空间,不容易造成内存碎片,空间利用率
高,缓存利用率高
底层节点动态开辟,小节点容易
造成内存碎片,空间利用率低,
缓存利用率低
原生态指针
对原生态指针 ( 节点指针 ) 进行封装
在插入元素时,要给所有的迭代器重新赋值,因为插入
元素有可能会导致重新扩容,致使原来迭代器失效,删
除时,当前迭代器需要重新赋值否则会失效
插入元素不会导致迭代器失效,
删除元素时,只会导致当前迭代
器失效,其他迭代器不受影响
使
需要高效存储,支持随机访问,不关心插入删除效率
大量插入和删除操作,不关心随
机访问

相关文章:

【c++_containers】10分钟带你学会list

前言 链表作为一个像是用“链子”链接起来的容器&#xff0c;在数据的存储等方面极为便捷。虽然单链表单独在实际的应用中没用什么作用&#xff0c;但是当他可以结合其他结构&#xff0c;比如哈希桶之类的。不过今天学习的list其实是一个带头双向链表。 言归正传&#xff0c;让…...

LeetCode 0714. 买卖股票的最佳时机含手续费

【LetMeFly】714.买卖股票的最佳时机含手续费 力扣题目链接&#xff1a;https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/ 给定一个整数数组 prices&#xff0c;其中 prices[i]表示第 i 天的股票价格 &#xff1b;整数 fee 代表了交易股…...

cartographer-(0)-ubuntu(20.04)-环境安装

1.安装 ROS wiki.ros.org 1.1修改镜像源&#xff1a; 到网站上找与操作系统相匹配的镜像源 ubuntu | 镜像站使用帮助 | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror # 默认注释了源码镜像以提高 apt update 速度&#xff0c;如有需要可自行取消注释 deb htt…...

MIT 6.S081学习笔记(第二章)

〇、前言 本文主要完成MIT 6.S081 实验二&#xff1a;system call 一、Using gdb (easy) Question requirements In many cases, print statements will be sufficient to debug your kernel, but sometimes being able to single step through some assembly code or inspe…...

L958. 二叉树的完全性检验 java

从1开始当下标&#xff0c;最后节点下标节点总数&#xff1f;true&#xff1a;false&#xff1b; /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { …...

阿里云对象存储OSS SDK的使用

官方文档 https://help.aliyun.com/zh/oss/developer-reference/java 准备工作 windows安装好JDK&#xff0c;这里使用JDK1.8为例 windows安装好IDEA&#xff0c;这里使用IDEA2022 登录阿里云控制台&#xff0c;通过免费试用OSS或开通OSS 步骤 配置访问凭证 有临时和长期…...

二、互联网技术——网络协议

文章目录 一、OSI与TCP/IP参考模型二、TCP/IP参考模型各层功能三、TCP/IP参考模型与对应协议四、常用协议与功能五、常用协议端口 一、OSI与TCP/IP参考模型 二、TCP/IP参考模型各层功能 三、TCP/IP参考模型与对应协议 例题&#xff1a;TCP/IP模型包含四个层次&#xff0c;由上至…...

初赛错题集

MPEG属于视频文件格式. UNIX,Mac OS属于操作系统. 中国计算机协会成立于&#xff08;&#xff09;年。 A. 1961 B. 1962 C. 1971 D. 1972 Ans:B 五个本质不同的点在没有重边或者自环的情况下&#xff0c;组成不同的无向图的个数是: A. 10 B. 1024 C. 15 D. 120 Ans:B 解析&…...

Java Thread类详解

&#x1f648;作者简介&#xff1a;练习时长两年半的Java up主 &#x1f649;个人主页&#xff1a;程序员老茶 &#x1f64a; ps:点赞&#x1f44d;是免费的&#xff0c;却可以让写博客的作者开兴好久好久&#x1f60e; &#x1f4da;系列专栏&#xff1a;Java全栈&#xff0c;…...

3_使用传统CNN网络训练图像分类模型

使用传统CNN网络训练图像分类模型 1. MNIST 首先,定义一下超参数等 import torch# dataset input_shape = 28 num_classes = 10# hyper batch_size = 64 num_epochs = 5 learning_rate = 1e-3# gpu device = torch.device(cuda...

Java 创建线程的方法

&#x1f648;作者简介&#xff1a;练习时长两年半的Java up主 &#x1f649;个人主页&#xff1a;程序员老茶 &#x1f64a; ps:点赞&#x1f44d;是免费的&#xff0c;却可以让写博客的作者开兴好久好久&#x1f60e; &#x1f4da;系列专栏&#xff1a;Java全栈&#xff0c;…...

基于安卓android微信小程序的旅游app系统

项目介绍 随着人民生活水平的提高,旅游业已经越来越大众化,而旅游业的核心是信息,不论是对旅游管理部门、对旅游企业,或是对旅游者而言,有效的获取旅游信息,都显得特别重要.自助定制游将使旅游相关信息管理工作规范化、信息化、程序化,提供旅游景点、旅游线路,旅游新闻等服务本…...

C++设计模式-单件(Singleton)

目录 C设计模式-单件&#xff08;Singleton&#xff09; 一、意图 二、适用性 三、结构 四、参与者 五、代码 C设计模式-单件&#xff08;Singleton&#xff09; 一、意图 保证一个类仅有一个实例&#xff0c;并提供一个访问它的全局访问点。 二、适用性 当类只能有一…...

想做好接口测试,先把这些概念搞清楚了

接口一般来说有两种&#xff0c;一种是程序内部的接口&#xff0c;一种是系统对外的接口。 系统对外的接口 比如你要从别的网站或服务器上获取资源或信息&#xff0c;别人肯定不会把数据库共享给你&#xff0c;他只能给你提供一个他们写好的方法来获取数据&#xff0c;你引用…...

通过融合UGV的地图信息和IMU的惯性测量数据,实现对车辆精确位置和运动状态的估计和跟踪研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

『Linux』Linux环境搭建 | 阿里云云服务器白嫖 | Xshell环境配置

&#x1f525;博客主页&#xff1a; 小羊失眠啦 &#x1f516;系列专栏&#xff1a; C语言、Linux &#x1f325;️每日语录&#xff1a;时间&#xff0c;都是公平的&#xff0c;不公平的&#xff0c;只是现在的自己&#xff0c;对未来的自己。 ❤️感谢大家点赞&#x1f44d;收…...

C++ 类和对象篇(五) 析构函数

目录 一、概念 1. 析构函数是什么&#xff1f; 2. 为什么要有析构函数&#xff1f; 3. 怎么用析构函数&#xff1f; 3.1 创建析构函数 3.2 调用析构函数 二、特性 三、由编译器生成的默认析构函数 四、对象的析构顺序 1. 局部对象 2. new出来的堆对象 3. 全局对象 一、概念 1…...

find 与 cp 命令组合使用

查找到文件后&#xff0c;拷贝到指定路径 find ~/Downloads/ -name *.torrent -exec cp {} ~/Downloads/myTorrent \;\;前面有个空格&#xff0c;要注意&#xff0c;这是固定结构&#xff0c;请不要尝试改变 上面命令是在Downloads 目标中查找后缀为torrent所有文件&#xff0…...

用VLD调查VC内存泄漏

一、发现内存泄漏 使用VS2022&#xff0c;发现提示有内存泄漏&#xff0c;检查了所有的new&#xff0c;确认都有相应的delete释放。 Detected memory leaks! Dumping objects -> {1914} normal block at 0x0000021FDFFBD2E0, 48 bytes long.Data: < >…...

【Java 进阶篇】使用 JDBCTemplate 执行 DQL 语句详解

在前面的文章中&#xff0c;我们已经学习了如何使用 Spring 的 JDBCTemplate 执行 DML&#xff08;Data Manipulation Language&#xff09;操作&#xff0c;包括插入、更新和删除操作。现在&#xff0c;让我们来深入了解如何使用 JDBCTemplate 执行 DQL&#xff08;Data Query…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2

每日一言 今天的每一份坚持&#xff0c;都是在为未来积攒底气。 案例&#xff1a;OLED显示一个A 这边观察到一个点&#xff0c;怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 &#xff1a; 如果代码里信号切换太快&#xff08;比如 SDA 刚变&#xff0c;SCL 立刻变&#…...

【Java学习笔记】BigInteger 和 BigDecimal 类

BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点&#xff1a;传参类型必须是类对象 一、BigInteger 1. 作用&#xff1a;适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...

2025季度云服务器排行榜

在全球云服务器市场&#xff0c;各厂商的排名和地位并非一成不变&#xff0c;而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势&#xff0c;对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析&#xff1a; 一、全球“三巨头”…...

中医有效性探讨

文章目录 西医是如何发展到以生物化学为药理基础的现代医学&#xff1f;传统医学奠基期&#xff08;远古 - 17 世纪&#xff09;近代医学转型期&#xff08;17 世纪 - 19 世纪末&#xff09;​现代医学成熟期&#xff08;20世纪至今&#xff09; 中医的源远流长和一脉相承远古至…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)

推荐 github 项目:GeminiImageApp(图片生成方向&#xff0c;可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...

【JavaSE】多线程基础学习笔记

多线程基础 -线程相关概念 程序&#xff08;Program&#xff09; 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序&#xff0c;比如我们使用QQ&#xff0c;就启动了一个进程&#xff0c;操作系统就会为该进程分配内存…...

【LeetCode】3309. 连接二进制表示可形成的最大数值(递归|回溯|位运算)

LeetCode 3309. 连接二进制表示可形成的最大数值&#xff08;中等&#xff09; 题目描述解题思路Java代码 题目描述 题目链接&#xff1a;LeetCode 3309. 连接二进制表示可形成的最大数值&#xff08;中等&#xff09; 给你一个长度为 3 的整数数组 nums。 现以某种顺序 连接…...

【LeetCode】算法详解#6 ---除自身以外数组的乘积

1.题目介绍 给定一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O…...

无需布线的革命:电力载波技术赋能楼宇自控系统-亚川科技

无需布线的革命&#xff1a;电力载波技术赋能楼宇自控系统 在楼宇自动化领域&#xff0c;传统控制系统依赖复杂的专用通信线路&#xff0c;不仅施工成本高昂&#xff0c;后期维护和扩展也极为不便。电力载波技术&#xff08;PLC&#xff09;的突破性应用&#xff0c;彻底改变了…...

Centos 7 服务器部署多网站

一、准备工作 安装 Apache bash sudo yum install httpd -y sudo systemctl start httpd sudo systemctl enable httpd创建网站目录 假设部署 2 个网站&#xff0c;目录结构如下&#xff1a; bash sudo mkdir -p /var/www/site1/html sudo mkdir -p /var/www/site2/html添加测试…...