C++ list的基本使用
目录
1.list简要介绍
2. list的构造
3. list中迭代器的使用
(1). 双向迭代器与随机访问迭代器使用区别
4.判空、获取元素个数
5. list头、尾元素的访问
6. 插入与删除操作
(1). 头插头删,尾插尾删
(2). 插入,删除与清空
(3). 交换
7. list容器迭代器失效问题
1.list简要介绍
在C++标准库中list是基于双向链表实现的
其特点主要包括
- 双向链表结构,插入和删除元素时非常高效,因为不需要移动元素
- 内存分配并不是连续的,和vector不同
- 不支持随机访问的迭代器,提供的迭代器是双向迭代器(下文会详细介绍)
- 可以动态增容,不受容量的限制
- 由于每个元素都需要额外的内存来存储指向相邻元素的指针(或引用),因此list可能会比基于数组的容器(如vector)使用更多的内存
2. list的构造
构造函数 | 接口说明 |
list(size_type n, const val_type& val = value_type() ) | 构造的list中包含n个值为val的元素 |
list() | 构造空的list |
list(const list& x) | 拷贝构造函数 |
list(InputIterator first,InputIterator last) | 用[first,last)区间中的元素构造list (左闭右开) |
演示代码如下
#include<iostream>
#include<list>using namespace std;int main()
{list<int> l1(10);for (auto ll : l1){cout << ll << " ";}cout << endl;list<int> l2(10, 3);for (auto ll : l2){cout << ll << " ";}cout << endl;list<int> l3(l1);for (auto ll : l3){cout << ll << " ";}cout << endl;list<int> l4(l2.begin(), l2.end());for (auto ll : l4){cout << ll << " ";}cout << endl;}
3. list中迭代器的使用
函数 | 接口说明 |
begin+end | 返回第一个元素的迭代器+返回最后一个元素下一个位置的迭代器 |
rbegin+rend | 返回第一个元素的reverse_iterator,即end位置,返回最后一个元素下一位的reverse_iterator,即begin位置 |
演示代码如下
#include<iostream>
#include<list>using namespace std;int main()
{list<int> l1(10);l1.push_back(1);list<int>::iterator il = l1.begin();while (il != l1.end()){cout << *il << " ";il++;}cout << endl;list<int>::reverse_iterator it = l1.rbegin();while(it!=l1.rend()){cout << *it << " ";it++;}cout << endl;}
输出结果为
这里的迭代器是双向迭代器(Bidirectional Iterator),vector与string等支持随机访问迭代器(Random Access Iterator)存在差异
(1). 双向迭代器与随机访问迭代器使用区别
双向迭代器可以使用++向前,使用--向后移动。支持基本迭代器操作如解引用( * )、自增自减(++ , --)和比较操作( == , != )
随机访问迭代器除了支持双向迭代器所有的功能外,还提供了快速随机访问容器中任意元素的能力。这意味着它支持指针算数运算,(假设v是一个对象)如v.begin()+n (向前移动n个位置),v.end()-n (向后移动n个位置),以及比较操作(< , <= , > , >=)
4.判空、获取元素个数
函数声明 | 接口说明 |
empty | 检测list是否为空,是返回true,否则返回false |
size | 返回list中有效节点的个数 |
简单演示代码如下
#include<iostream>
#include<list>using namespace std;int main()
{list<int> l1(10);list<int> l2;cout << "l1元素个数为:" << l1.size() << endl;cout << "l2元素个数为:" << l2.size() << endl;cout << "l1是否为空?" << endl;if (l1.empty())cout << "yes" << endl;elsecout << "no" << endl;cout << "l2是否为空?" << endl;if (l2.empty())cout << "yes" << endl;elsecout << "no" << endl;l1.push_back(1);l2.push_back(66);cout << "l1元素个数为:" << l1.size() << endl;cout << "l2元素个数为:" << l2.size() << endl;cout << "l1是否为空?" << endl;if (l1.empty())cout << "yes" << endl;elsecout << "no" << endl;cout << "l2是否为空?" << endl;if (l2.empty())cout << "yes" << endl;elsecout << "no" << endl;}
输出结果如下
5. list头、尾元素的访问
函数声明 | 接口说明 |
front | 返回list第一个节点中值的引用 |
back | 返回list的最后一个节点中值的引用 |
演示代码如下
#include<iostream>
#include<list>using namespace std;int main()
{list<int> l1(10);list<int> l2;cout<<l1.front()<<endl;int& f = l1.front();//可用引用接收l1.push_front(4);cout << f<<endl;cout << l1.front() << endl;cout << l1.back() << endl;int& t = l1.back();cout << t << endl;l1.push_back(6);cout << l1.back();//cout << l2.front();//cout << l2.back();return 0;
}
特别注意如果list为空使用会报错
6. 插入与删除操作
函数 | 接口说明 |
push_front | 在list首元素前插入值为val的元素 |
pop_front | 删除list中第一个元素 |
push_back | 在list尾部插入值为val的元素 |
pop_back | 删除list中最后一个元素 |
insert | 在list 中的指定位置pos插入值为val的元素 |
erase | 删除list指定位置pos的元素 |
clear | 清空list中的有效元素 |
swap | 交换两个list中的元素 |
(1). 头插头删,尾插尾删
代码简单演示
#include<iostream>
#include<list>using namespace std;int main()
{list<int> ll;ll.push_back(8);ll.push_back(5);ll.push_back(2);ll.push_front(9);ll.push_front(6);ll.push_front(3);for (auto l : ll){cout << l << " ";}cout << endl;ll.pop_back();ll.pop_front();for (auto l : ll){cout << l << " ";}cout << endl;
}
(2). 插入,删除与清空
演示代码如下
#include<iostream>
#include<list>
#include<vector>
using namespace std;template<class T>
void print_list(list<T> ll)
{for (auto l : ll){cout << l << " ";}cout << endl;
}
int main()
{int array1[] = { 1, 2, 3 };list<int> L(array1, array1 + sizeof(array1) / sizeof(array1[0]));// 获取链表中第二个节点auto pos = ++L.begin();cout << *pos << endl;print_list(L);
// 在pos前插入值为4的元素L.insert(pos, 4);print_list(L);
// 在pos前插入5个值为5的元素L.insert(pos, 5, 5);print_list(L);// 在pos前插入[v.begin(), v.end)区间中的元素vector<int> v{ 7, 8, 9 };L.insert(pos, v.begin(), v.end());print_list(L);// 删除pos位置上的元素L.erase(pos);print_list(L);list<int> LL(L);
// 删除list中[begin, end)区间中的元素,即删除list中的所有元素L.erase(L.begin(), L.end());print_list(L);cout << "LL元素个数为: " << LL.size() << endl;LL.clear();cout << "LL元素个数为: " << LL.size() << endl;}
输出结果为
(3). 交换
演示代码如下
#include<iostream>
#include<list>
#include<vector>
using namespace std;template<class T>
void print_list(list<T> ll)
{for (auto l : ll){cout << l << " ";}cout << endl;
}
int main()
{int array1[] = { 1, 2, 3 };list<int> L1(array1, array1 + sizeof(array1) / sizeof(array1[0]));list<int> L2;cout << "L1: ";print_list(L1);cout << "L2: ";print_list(L2);L1.swap(L2);cout << "L1: ";print_list(L1);cout << "L2: ";print_list(L2);return 0;
}
输出结果如下
list提供的swap成员函数优化了交换操作,使其可以在常数时间内完成std::swap 也可以交换list对象,但不如list自己的成员函数,实际上它只用交换两个list对象的头指针和尾指针时间复杂度通常为O(1),不涉及元素的实际移动或复制
7. list容器迭代器失效问题
迭代器失效即迭代器所指向的节点无效,即该节点被删除了。因为list底层结构为带头节点的双向循环链表,所以在list中进行插入时是不会导致list的迭代器失效的,只有在删除时才会失效并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响(与vector不同,list每个节点存储不是连续的)。
eraser比较容易触发
#include<iostream>
#include<list>
using namespace std;
int main()
{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()){// erase()函数执行后,it所指向的节点已被删除,因此it无效,在下一次使用it时,必须先给//其赋值cout << *it << " ";l.erase(it);++it;}return 0;
}
输出结果如下
在执行删除后迭代器就失效了
解决方法1
#include<iostream>
#include<list>
using namespace std;
int main()
{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()){cout << *it << " ";l.erase(it++); }return 0;
}
利用后置++先使用,在迭代器失效前提前改变了迭代器的值
解决方法2
while (it != l.end()){cout << *it << " ";it=l.erase(it); // it = l.erase(it);}
使用it来接收删除数据后的返回的迭代器
8. list与vector的区别
vector | list | |
底层结构 | 动态顺序表,一段连续空间 | 带头节点的双向循环链表 |
随机访问 | 支持随机访问,访问某个元素效率O(1) | 不支持随机访问,访问某个元素效率O(N) |
插入和删除 | 任意位置插入和删除效率低,需要搬移元素,时间复杂度为O(N),插入时有可能需要增容,增容:开辟新空间,拷贝元素,释放旧空间,导致效率更低 | 任意位置插入和删除效率高,不需要搬移元素,时间复杂度为O(1) |
空间利用率 | 底层为连续空间,不容易造成内存碎片,空间利用率高,缓存利用率高 | 底层节点动态开辟,小节点容易造成内存碎片,空间利用率低,缓存利用率低 |
迭代器 | 原生态指针 | 对原生态指针(节点指针)进行了封装 |
迭代器失效 | 在插入元素时,要给所有迭代器重新赋值,因为插入元素有可能会导致重新扩容,导致原来迭代器失效。删除时,当前迭代器需要重新赋值否则会失效 | 插入元素不会导致迭代器失效,删除元素时,只会导致当前迭代器失效需要重新赋值,其他迭代器不受影响 |
使用场景 | 需要高效存储,支持随机访问,不关心插入删除的效率 | 大量插入和删除操作,不关心随机访问 |
这篇就到这里啦,感谢阅读
(๑′ᴗ‵๑)I Lᵒᵛᵉᵧₒᵤ❤
相关文章:

C++ list的基本使用
目录 1.list简要介绍 2. list的构造 3. list中迭代器的使用 (1). 双向迭代器与随机访问迭代器使用区别 4.判空、获取元素个数 5. list头、尾元素的访问 6. 插入与删除操作 (1). 头插头删,尾插尾删 (2). 插入,删除与清空 (3). 交换 7. list容器迭代…...

云中韧性:Spring Cloud服务调用重试机制深度解析
标题:云中韧性:Spring Cloud服务调用重试机制深度解析 在微服务架构中,服务间的调用可能会因为网络问题、服务不可达、资源竞争等原因失败。Spring Cloud作为微服务架构的主流实现框架,提供了一套完整的服务调用重试机制…...

83.SAP ABAP从前台找字段所在表的两种方法整理笔记
目录 方法1:F1查看技术信息 F1 技术信息 方法2:ST05开启跟踪 Activate Trace Input and save data Deactivate Trace Display Trace 分析你想要的表 方法1:F1查看技术信息 从前台找一个屏幕字段所在表,一般通过按F1来查找…...

docker为普通用户设置sudo权限
在 Linux 上使用 Docker 命令时,默认情况下需要 sudo 权限。这是因为 Docker 守护进程(Docker daemon)通常运行在 root 用户下,而访问和管理 Docker 守护进程的权限也默认被限制给 root 用户。 然而,为了方便日常使用…...

Nginx + PHP 8.0支持视频上传
在 Ubuntu 20.04 上配置 Nginx PHP 8.0 的架构以支持视频上传,需要从 Nginx 和 PHP 两个方面进行配置,以确保服务器能够处理大文件上传。以下是详细的步骤: 1. Nginx 配置 1.1 增加上传文件大小限制 默认情况下,Nginx 对上传文…...

MySQL基础详解(3)
文章目录 索引普通索引创建索引修改表结构(添加索引)创建表的时候直接指定删除索引的语法 唯一索引创建索引修改表结构创建表的时候直接指定 使用ALTER 命令添加和删除索引使用ALTER 命令添加和删除主键显示索引信息 约束非空约束:唯一约束:主键约束&…...

傅里叶变换结合数学形态学进行边缘增强和边缘提取
一、前言 傅里叶变换是图像变换的一种常用方法,傅里叶变换在图像处理中扮演着核心角色,它通过将图像从空间域转换到频率域,获取图像的频率成分,因为有些特征在空间域很难处理,但在频率域比较容易处理。这一转换有助于分…...

Haproxy的ACL介绍及应用实例
一、ACL介绍 访问控制列表ACL,Access Control Lists) 是一种基于包过滤的访问控制技术 它可以根据设定的条件对经过服务器传输的数据包进行过滤(条件匹配)即对接收到的报文进行匹配和过 滤,基于请求报文头部中的源地址、源端口、目标地址、目…...

final finally finalize 区别?
final: final 是一个修饰符,可以用于类、方法和变量。当final修饰类时,表示该类不能被继承。当final修饰方法时,表示该方法不能被子类覆盖(重写)。当final修饰变量时,表示该变量是一个常量,其值…...

C语言常用的内存函数
在上一篇博客中我为大家分享了一些常用的字符串函数,以及它们的用法和模拟实现。通过字符串函数中的strcpy,我们能够做到将一个字符串中的内容拷贝到另一个字符串上,可如果有一天我们想把一个整型数组中的内容拷贝到另一个整型数组中呢&#…...

MP4 H.264 MPEG-4 MPEG-2
MP4 视频编解码技术 H.264 MPEG-4 MPEG-2 MP4 (MPEG-4 Part 14): Format: A digital multimedia container format.Use: Often used to store video, audio, subtitles, and still images.Compression: Can use different codecs, such as H.264, for video compression. H.264…...

nvm 切换、安装 Node.js 版本
nvm下载路径 往下拉找到Assets 下载后,找到nvm-setup.exe双击,一直无脑下一步,即可安装成功。 配置环境变量(我的是window11) 打开任务栏设置–搜环境变量 配置好后,点确定一层一层关闭 windowR 打开控制…...

基于区块链的合同存证应用开发
基于区块链的合同存证应用开发 任务一:环境准备 1.启动区块链网络 目录: /root/xuperchain/output/ 启动区块链网络 bash constrol.sh start2.创建钱包账户 目录: /root/xuperchain/output/ 创建tenant, landlord钱包账户,命令如下: bin/xchain-cli account newke…...

每日一题~ abc 365 E 异或运算(拆位+贡献)
处理位运算常用的方法: 拆位法(一位一位的处理,通常题目中会给出元素的最大是2的的多少次幂,当然也有给10的次幂的,自己注意一下就可以了) 常用的思想 : 算贡献。 异或的性质: A^A0 …...

前端八股文笔记【三】
JavaScript 基础题型 1.JS的基本数据类型有哪些 基本数据类型:String,Number,Boolean,Nndefined,NULL,Symbol,Bigint 引用数据类型:object NaN是一个数值类型,但不是…...

AI学习记录 - transformer的Embedding层
创作不易,免费的赞 前面有介绍了GPT2如何进行token化的过程,现在讲下transformer的Embedding层 Embedding层就是一个巨大的矩阵,边长分别是词汇表长度和词向量维度,矩阵里面的每一个数字都是一个随机初始化的,或者是…...

23-PCB封装名称的统一添加与管理
1.进入封装管理器 2. 选择对象,点击右侧添加按钮 3. 搜索所需要的封装 4.接受创建变更 5.执行变更 6.关闭...

【Python从入门到进阶】62、Pandas中DataFrame对象案例实践
接上篇《61、Pandas中DataFrame对象的操作(二)》 上一篇我们讲解DataFrame对象的统计分析、可视化以及数据导出与保存相关内容。本篇我们延续之前学习的DataFrame对象的知识,结合一个数据案例进行实践操作。 一、案例说明 我们将通过一个股…...

使用Python实现深度学习模型:智能环境监测与预警
介绍 智能环境监测与预警是保护生态环境和人类健康的重要手段。通过深度学习技术,我们可以实时获取环境数据,分析环境变化趋势,及时发出预警。本文将介绍如何使用Python和深度学习库TensorFlow与Keras来构建一个简单的环境监测与预警模型。 环境准备 首先,我们需要安装必…...

ThreadLocal的使用场景是什么
ThreadLocal 是 Java 中用于实现线程局部变量的工具,它提供了每个线程独立的变量副本,使得不同线程对该变量的操作不会相互干扰。以下是 ThreadLocal 的常见使用场景: 线程安全的对象共享: ThreadLocal 可以用来避免线程间共享状…...

【网络爬虫篇】逆向实战—某东:滑块验证码(逆向登录)2024.8.7最新发布,包干货,包详细
【网络爬虫篇】更多优秀文章借鉴: 1. 使用Selenium实现黑马头条滑块自动登录 2. 使用多线程采集爬取豆瓣top250电影榜 3. 使用Scrapy爬取去哪儿网游记数据 4. 数据采集技术综合项目实战1:国家水稻网数据采集与分析 5. 数据采集技术综合项目实战2&#x…...

为什么优质的酱香白酒都会带点苦味?
大家好,我是酱酒亮哥,不知大家有没有发现,在制作一杯美味的咖啡或是烘焙一块香脆的面包时,制作过程中都会有一些独特的味道和香气产生,对吧?同样地,酱香白酒的酿造过程也是一个复杂而精细的化学…...

软件测试常见面试题
软件测试阶段分为单元测试,集成测试,系统测试,验收测试。单元测试策略为对代码中的函数方法进行测试,目的是发现代码的问题。集成测试策略是模块中组合起来进行测试,要求发现与接口有关的问题。系统测试策略是子系统的…...

面试经典算法150题系列-接雨水
接雨水 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 示例 1: 输入:height [0,1,0,2,1,0,1,3,2,1,2,1] 输出:6 解释:上面是由数组 [0,1,0,2,1,0,1,3,2,…...

【C++】 类型转换深度探索:揭开类型转换的奥秘
🌈 个人主页:Zfox_ 🔥 系列专栏:C从入门到精通 目录 一: 🚀 C语言中的类型转换 二: 🔥 为什么C需要四种类型转换 三: 🔥 C强制类型转换 🥝 3.1 st…...

深入探索Webkit的Web Authentication API:安全与便捷的融合
Web Authentication API,通常被称为WebAuthn,是一个新兴的Web标准,旨在通过提供更安全、更便捷的认证方式来改善用户的在线体验。随着Webkit对WebAuthn的支持日益增强,本文将深入探讨这一API的功能、实现方式以及如何在Webkit浏览…...

Vue - 关于v-wave 波浪动画组件
Vue - 关于v-wave 波浪动画组件 这个动画库可以在标签中添加新的v-wave属性,来让点击标签元素后添加漂亮的波纹效果,并且可以根据父元素自动形成波纹的颜色,也可以自定义波纹颜色,持续时间,透明度,触发的对…...

计算机网络408考研 2019
计算机网络408考研2019年真题解析_哔哩哔哩_bilibili 2019 1 1 1 1...

实时捕捉与追溯:得物基于 eBPF 打造云上网络连接异常摄像头
近期我们容器 SRE 团队基于 eBPF 技术建设网络连接异常感知能力,灰度上线过程中发现了生产环境 10 以上的应用配置错误、程序 Bug 等问题。在和应用负责同学同步风险过程中,大家都挺好奇我们如何实现在对应用无侵入的情况下发现服务连接异常的。本篇文档…...

ubuntu14.04图形界面配置
Ubuntu系统启动,输入用户密码后,屏幕显示彩色背景,但是始终不能进入图形界面。 如果你也遇到过这种情况,可以参照以下方法解决(在 ubuntu14.04 验证)。 同时按下 alt ctrl F1,屏幕出现 tty1&a…...