【C++初阶】第十一站:list的介绍及使用
目录
list的介绍及使用
1.list的含义
2.list的介绍
3.list的使用
1.list的构造
2.list iterator的使用
3.list capacity
4.list element access
5 list modifiers
尾插尾删 和 头插头删
insert 和 erase
resize swap clear
6.list sort and reverse
7.list copy vector copy list
8.splice
9 list的迭代器失效
前言:
🎯个人博客:Dream_Chaser
🎈博客专栏:C++
📚本篇内容:list的介绍及使用
list的介绍及使用
1.list的含义

列表是序列容器,允许在序列内的任何位置进行常量时间的插入和删除操作,以及两个方向的迭代。

容器的分类:

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

3.list的使用
list中的接口比较多,此处类似,只需要掌握如何正确的使用,然后再去深入研究背后的原理,已达到可扩展的能力。以下为list中一些常见的重要接口
1.list的构造
| 构造函数( (constructor)) | 接口说明 |
| list (size_type n, const value_type& val = value_type()) | 构造的 list 中包含 n 个值为 val 的元素 |
| list() | 构造空的 list |
| list (const list& x) | 拷贝构造函数 |
| list (InputIterator first, InputIterator last) | 用 [first, last) 区间中的元素构造 list |

void TestList1()
{list<int> l1; // 构造空的l1list<int> l2(4, 100); // l2中放4个值为100的元素list<int> l3(l2.begin(), l2.end()); // 用l2的[begin(), end())左闭右开的区间构造l3list<int> l4(l3); // 用l3拷贝构造l4// 以数组为迭代器区间构造l5int array[] = { 16,2,77,29 };list<int> l5(array, array + sizeof(array) / sizeof(int));// 列表格式初始化C++11list<int> l6{ 1,2,3,4,5 };// 用迭代器方式打印l5中的元素list<int>::iterator it = l5.begin();while (it != l5.end()){cout << *it << " ";++it;}cout << endl;// C++11范围for的方式遍历for (auto& e : l5)cout << e << " ";cout << endl;
}
2.list iterator的使用
此处,大家可暂时将迭代器理解成一个指针,该指针指向list中的某个节点。
| 函数声明 | 接口说明 |
| begin + end | 返回第一个元素的迭代器 + 返回最后一个元素下一个位置的迭代器 |
| rbegin + rend | 返回第一个元素的 reverse_iterator, 即 end 位置 , 返回最后一个元素下一个位置的 reverse_iterator, 即 begin 位置 |

【注意】
1. begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动
2. rbegin(end)与rend(begin)为反向迭代器,对迭代器执行++操作,迭代器向前移动

void TestList2()
{int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };list<int> l(array, array + sizeof(array) / sizeof(array[0]));// 使用正向迭代器正向list中的元素// list<int>::iterator it = l.begin(); // C++98中语法auto it = l.begin(); // C++11之后推荐写法while (it != l.end()){cout << *it << " ";++it;}cout << endl;// 使用反向迭代器逆向打印list中的元素// list<int>::reverse_iterator rit = l.rbegin();auto rit = l.rbegin();while (rit != l.rend()){cout << *rit << " ";++rit;}cout << endl;
}
3.list capacity


#include <iostream>
#include <list>int main() {// 创建一个std::list并添加几个元素std::list<int> numbers = { 1, 2, 3, 4, 5 };// 使用size()方法打印列表中的元素数量std::cout << "The list contains " << numbers.size() << " elements." << std::endl;// 使用empty()方法检查列表是否为空,并打印结果if (numbers.empty()) {std::cout << "The list is empty." << std::endl;}else {std::cout << "The list is not empty." << std::endl;}// 移除所有元素后,再次使用empty()检查numbers.clear();if (numbers.empty()) {std::cout << "After clearing, the list is now empty." << std::endl;}return 0;
}
4.list element access
| 函数声明 | 接口说明 |
| front | 返回 list 的第一个节点中值的引用 |
| back | 返回 list 的最后一个节点中值的引用 |
5 list modifiers
| 函数声明 | 接口说明 |
| push_front | 在 list 首元素前插入值为 val 的元素 |
| pop_front | 删除 list 中第一个元素 |
| push_back | 在 list 尾部插入值为 val 的元素 |
| pop_back | 删除 list 中最后一个元素 |
| insert | 在 list position 位置中插入值为 val 的元素 |
| erase | 删除 list position 位置的元素 |
| swap | 交换两个 list 中的元素 |
| clear | 清空 list 中的有效元素 |
尾插尾删 和 头插头删

/ list迭代器的使用
// 注意:遍历链表只能用迭代器和范围for
void PrintList(const list<int>& l)
{// 注意这里调用的是list的 begin() const,返回list的const_iterator对象for (list<int>::const_iterator it = l.begin(); it != l.end(); ++it){cout << *it << " ";// *it = 10; 编译不通过}cout << endl;
}//list插入和删除
// push_back/pop_back/push_front/pop_front
void TestList3()
{int array[] = { 1, 2, 3 };list<int> L(array, array + sizeof(array) / sizeof(array[0]));// 在list的尾部插入4,头部插入0L.push_back(4);L.push_front(0);PrintList(L);// 删除list尾部节点和头部节点L.pop_back();L.pop_front();PrintList(L);
}
insert 和 erase

// insert /erase
void TestList4()
{int array1[] = { 1, 2, 3 };list<int> L(array1, array1 + sizeof(array1) / sizeof(array1[0]));// 获取链表中第二个节点auto pos = ++L.begin();cout << *pos << endl;// 在pos前插入值为4的元素L.insert(pos, 4);PrintList(L);// 在pos前插入5个值为5的元素L.insert(pos, 5, 5);PrintList(L);// 在pos前插入[v.begin(), v.end)区间中的元素vector<int> v{ 7, 8, 9 };L.insert(pos, v.begin(), v.end());PrintList(L);// 删除pos位置上的元素L.erase(pos);PrintList(L);// 删除list中[begin, end)区间中的元素,即删除list中的所有元素L.erase(L.begin(), L.end());PrintList(L);
}
resize swap clear

void TestList5()
{// 用数组来构造listint array1[] = { 1, 2, 3 };list<int> l1(array1, array1 + sizeof(array1) / sizeof(array1[0]));PrintList(l1);// 交换l1和l2中的元素list<int> l2;l1.swap(l2);PrintList(l1);PrintList(l2);// 将l2中的元素清空l2.clear();cout << l2.size() << endl;
}
6.list sort and reverse

void test_list2()
{list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(5); for (auto e : lt){cout << e << " ";}cout << endl;lt.reverse();for (auto e : lt){cout << e << " ";}cout << endl;//sort(lt.begin(), lt.end());//为什么这个不能用呢?那是因为,list是双向迭代器//而标准库里面的sort支持随机迭代器,要用list自己的sort函数 lt.sort//升序 < lesslt.sort();//降序 > greater();//greater<int> gt;//lt.sort(gt);//匿名对象的排序,降序lt.sort(greater<int>());for (auto e : lt){cout << e << " ";}cout << endl;
}
7.list copy vector copy list
代码测这种性能要把它换成 Release,debug的优化没有全开的,导致递归和循环,次数比较多,差异是比较大的,但是Release的差距不大。

void test_op()
{ // 初始化随机数生成器,使用当前时间作为种子srand(time(0));// 定义常量N,表示要生成的随机数个数const int N = 1000000;//创建两个空的list容器list<int> lt1;list<int> lt2;// 循环N次,生成随机数并将其添加到两个list中for (int i = 0; i < N; i++){auto e = rand(); // 生成一个随机数lt1.push_back(e); // 将随机数添加到lt1的末尾lt2.push_back(e); // 将相同的随机数添加到lt2的末尾}// 记录开始时间,单位为clock ticks(时钟滴答)int begin1 = clock();//返回程序所消耗的处理器时间。// 创建一个vector,使用lt2的begin和end迭代器初始化,复制lt2的内容vector<int> v(lt2.begin(), lt2.end());// 对vector v 进行排序,使用的是全局的std::sort函数,vector支持随机访问迭代器sort(v.begin(),v.end());// 将排序后的vector v的内容重新赋值给lt2,替换lt2当前的内容。lt2.assign(v.begin(),v.end());int end1 = clock(); // 记录结束时间int begin2 = clock(); // 记录另一个操作的开始时间lt1.sort(); // 直接对lt1进行排序,使用list容器自带的sort成员函数int end2 = clock(); // 记录结束时间// 输出两次排序操作所花费的时间(单位为clock ticks)printf("list copy vector sort copy list sort:%d\n",end1 - begin1);printf("list sort:%d\n",end2 - begin2);
}
8.unique and remove

void test_list4()
{list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(3);lt.push_back(3);lt.push_back(3);lt.push_back(5);lt.push_back(5);lt.push_back(3);for (auto e : lt){cout << e << " ";}cout << endl;lt.sort();lt.unique();//去掉重复的for (auto e : lt){cout << e << " ";}cout << endl;//lt.remove(30);//删除不存在的,不会报错lt.remove(3);for (auto e : lt){cout << e << " ";}cout << endl;
}
8.splice
将元素从x转移到容器中,并将它们插入位置。


void test_list5()
{list<int> mylist1, mylist2;list<int>::iterator it;for (int i = 1; i <= 4; ++i){mylist1.push_back(i);//mylist1: 1 2 3 4}for (int i = 1; i <= 3; i++){mylist2.push_back(i*10);//mylist2:10 20 30}it = mylist1.begin();++it; //指向mylist1里面的2元素for (auto e : mylist1){cout << e << " ";}cout << endl;for (auto e : mylist2){cout << e << " ";}cout << endl;//mylist1.splice(it,mylist2);//mylist1:1 10 20 30 2 3 4//mylist2(empty)//"it" still points to 2 (the 5th element)//mylist1.splice(it, mylist2, ++mylist2.begin());//mylist:1 20 2 3 4//mylist1: 1 20 30 2 3 4mylist1.splice(it, mylist2, ++mylist2.begin(), mylist2.end());//mylist1:1 20 30 2 3 4 for (auto e : mylist1){cout << e << " ";}cout << endl;for (auto e : mylist2){cout << e << " ";}cout << endl;
}
9 list的迭代器失效
前面说过,此处大家可将迭代器暂时理解成类似于指针,迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。

pos这个位置使用完毕就失效了:
改正:
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);}
}
🔧本文修改次数:0
🧭更新时间:2024年 5 月 14 日
相关文章:
【C++初阶】第十一站:list的介绍及使用
目录 list的介绍及使用 1.list的含义 2.list的介绍 3.list的使用 1.list的构造 2.list iterator的使用 3.list capacity 4.list element access 5 list modifiers 尾插尾删 和 头插头删 insert 和 erase resize swap clear 6.list sort and reverse 7.list copy vector copy li…...
【devops】Linux 日常磁盘清理 ubuntu 清理大文件 docker 镜像清理
日常磁盘清理 1、查找大文件 find / -type f -size 1G2、清理docker无用镜像(drone产生的残余镜像文件) docker system prune -a一、清理服务器磁盘 1、查找大文件 在Ubuntu系统中,你可以使用find命令来查找大文件。find命令是一个强大的…...
2024年资阳市企业技术中心申报条件、流程要求及支持政策须知
第一章 总则 第一条 为深入贯彻中央、省、市大力实施创新驱动发展战略的部署要求,进一步强化企业技术创新主体地位,引导和支持企业增强技术创新能力,健全技术创新市场导向机制,规范我市企业技术中心(下称“市企业技术…...
社交媒体数据恢复:如流
如流,原名百度Hi,是百度公司开发的一款即时通讯软体。百度Hi具备文字消息、视讯、通话、文件传输等功能。 查找备份:如果您之前有备份如流中的数据,您可以尝试从备份中恢复。如流支持备份至云端,如百度网盘等。 联系客…...
【微信小程序开发(从零到一)【婚礼邀请函】制作】——任务分析和效果实现的前期准备(1)
👨💻个人主页:开发者-曼亿点 👨💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨💻 本文由 曼亿点 原创 👨💻 收录于专栏:…...
独孤思维:模仿别人赚钱太难,很痛苦
01 独孤早年混群的时候,想着成为群红,引流。 结果不得其法,别人要什么项目,我就把满是钩子的副业资料发群里。 被群主踢了出去。 我当时还不理解。 后来自己做了社群以后,才明白,这种行为,…...
图片转base64【Vue + 纯Html】
1.template <el-form-item label"图片"><div class"image-upload-container"><input type"file" id"imageUpload" class"image-upload" change"convertToBase64" /><label for"imageU…...
【从零开始学习Redis | 第十一篇】快速介绍Redis持久化策略
前言: Redis 作为一种快速、高效的内存数据库,被广泛应用于缓存、消息队列、会话存储等场景。然而,由于其特性是基于内存的,一旦服务器进程退出,内存中的数据就会丢失。为了解决这一问题,Redis 提供了持久…...
在Ubuntu中如何解压zip压缩包??
2024年5月15日,周三上午 使用 unzip 命令 unzip 文件名.zip这会将压缩包中的内容解压到当前目录。如果想解压到特定目录,可以使用 -d 选项,例如: unzip 文件名.zip -d 目标目录使用 7-zip 还可以安装 7-zip 工具来解压 ZIP 文件。…...
LeetCode 126题:单词接龙 II
❤️❤️❤️ 欢迎来到我的博客。希望您能在这里找到既有价值又有趣的内容,和我一起探索、学习和成长。欢迎评论区畅所欲言、享受知识的乐趣! 推荐:数据分析螺丝钉的首页 格物致知 终身学习 期待您的关注 导航: LeetCode解锁100…...
5.14(Vue2)
1.单页应用程序是指所有功能都在一个html页面上 单页面应用程序,之所以开发效率高,性能好,应用体验好,最大的原因就是:页面按需更新。 2.Vue中的路由 路径和组件的映射关系 Vue中的路由插件:VueRouter&…...
使用openssl生成自签名证书
使用openssl生成自签名证书 1. 交互式生成2. 一步生成参考 1. 交互式生成 自签名 SSL 证书的生成涉及一个简单的 3 步过程: 步骤 1:创建服务器私钥 openssl genrsa -out cert.key 2048步骤 2:创建证书签名请求 (CSR) openssl req -new -k…...
【java】泛型
文章目录 1. 什么是泛型?1.1 背景1.2 泛型的概念1.3 泛型的好处 2. 泛型类、接口...2.1 泛型类2.2 从泛型类派生子类2.2.1 子类也是泛型类,子类和父类的泛型类型要一致2.2.2 子类不是泛型类,父类要明确泛型的数据类型 2.3 泛型接口2.4 泛型方…...
计算思维的理解
2006年,卡内基梅隆大学周以真教授首次系统性地定义了计算思维。这一年,她在美国计算机权威期刊《Communications of the ACM》上发表了题为《Computational Thinking》的论文,由此开启了计算思维大众化的全新历程。 周以真(Jeanne…...
Python中tkinter编程入门4
在Python中tkinter编程入门3-CSDN博客中创建了Button控件,点击该控件就会产生一个点击事件,在创建Button控件时指定该点击事件的处理程序后,按键控件就会对用户的点击事件产生响应。 1 定义事件处理器 定义事件处理器就是一个自定义的函数。…...
Milvus的系统架构
简介 Milvus的构建在许多知名的向量搜索库比如Faiss, HNSW, DiskANN, SCANN等之上的,它针对稠密向量数据集的相似搜索而设计,能支持百万、十亿甚至万亿级别的向量搜索。 Milvus支持数据分片,流式数据插入,动态schema,…...
MFC中关于CMutex类的学习
MFC中关于CMutex类的学习 最近在项目中要实现两个线程之间的同步,MFC中提供了4个类,分别是CMutex(互斥量)、CCriticalSection(临界区)、CEvent(事件对象)、CSemaphore(信号量)。有关这4个类的说明,大家可以参考微软官方文档: CM…...
删除表空间
Oracle从入门到总裁:https://blog.csdn.net/weixin_67859959/article/details/135209645 当某个表空间中的数据不再需要时,或者新创建的表空间不符合要求时,可以考虑删除这个表空间。若要删除表空间,则需要用户具有 DROP TABLESP…...
下载element-ui报错
此错误表示尝试从npm注册表下载“resize observer polyfill”包时超时。这可能是由于网络连接问题或npm注册表服务器的问题。 要解决此问题,您可以尝试以下步骤: 1.重试npm install命令:有时,网络问题会导致临时超时。再次运行npm…...
[原创](Modern C++)现代C++的std::bind花式绑定,使用方式大全.
[简介] 常用网名: 猪头三 出生日期: 1981.XX.XX QQ联系: 643439947 个人网站: 80x86汇编小站 https://www.x86asm.org 编程生涯: 2001年~至今[共22年] 职业生涯: 20年 开发语言: C/C、80x86ASM、PHP、Perl、Objective-C、Object Pascal、C#、Python 开发工具: Visual Studio、D…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...
vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...
在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...
mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...
用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...
