【C++】介绍STL中list容器的常用接口

目录

一、STL中的list简介

二、构造函数

2.1 默认构造函数

2.2 填充构造(用n个相同的值构造)

2.3 迭代器构造 

2.4 拷贝构造和赋值运算符重载 

三、迭代器

3.1 正向迭代器

3.2 反向迭代器

四、容量相关 

4.1 获取list中有效数据的个数

4.2 判断list是否为空 —— empty

五、元素访问

5.1 获取第一个有效节点的数据

5.2 获取最后一个有效节点的数据

六、修改相关

6.1 头插、尾插 —— push_front、push_back

6.2 尾插、尾删 —— pop_front、pop_back 

6.3 在任意位置插入

6.4 在任意位置删除 —— erase

6.5 交换两个list对象

6.6 清空list中的有效节点

七、链表操作

7.1 将一个list上的数据转移到另一个list —— splice

7.2 删除某个特定数据

7.3 给数据排序 —— sort

7.4 去除重复数据 —— unique

7.5 反转数据 —— reverse

八、list与vector的对比 


一、STL中的list简介

1. list是可以在常数时间(O(1))内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代

2. listforward_list非常相似,最主要的不同在于forward_list是单链表,只能向前迭代,这让forward_list更简单高效。

3. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。

4. 与其他的序列式容器(arrayvector等)相比,list通常在任意位置进行插入、移除元素的执行效率更好。

5. 与其他序列式容器相比,listforward_list最大的缺陷是不支持任意位置的随机访问,必须从已知的位置(比如头部或者尾部)迭代到目标位置,而迭代到目标位置需要线性的时间(O(n))开销;除此之外list还需要一些额外的空间,以保存每个节点的相关联系。

【文档描述】


二、构造函数

2.1 默认构造函数

【代码演示】

#include <iostream>
#include <list>
#include <string>
using namespace std;int main()
{//默认拷贝拷贝构造 list<T> lt;(T为list存储的数据类型)list<string> ls;return 0;
}

【输出结果】

        注:list不像stringvectorlist没有容量capacity这个属性。 


2.2 填充构造(用n个相同的值构造)

【代码演示】

#include <iostream>
#include <list>
using namespace std;int main()
{//填充构造    list (size_type n, const value_type& val = value_type())list<int> li(5, 20);//如果不指定val的值就会初始化为相应类型的默认值//int为0 double为0.0 char为'\0'……list<double> ld(3);for (const auto& k : li){cout << k << " ";}cout << endl;for (const auto& k : ld){cout << k << " ";}cout << endl;return 0;
}

【输出结果】


2.3 迭代器构造 

【代码演示】

#include <iostream>
#include <list>
#include <string>
using namespace std;int main()
{//迭代器构造 list (InputIterator first, InputIterator last) //迭代器区间为左闭右开 -》 [first, last)//用数组构造int array[] = { 1,2,3,4,5,6 };list<int> li(array, array + sizeof(array) / sizeof(array[0]));//这个其实是先用数组构造了一个list<int> temp //然后用拷贝构造将temp拷贝给了li_another -》 list<int> li_another(temp)list<int> li_another{ 1,2,3,4,5 };//可以用别的容器的迭代器来构造liststring s("Hello list!");list<char> lc(s.begin(), s.end());//可以用list的迭代器来构造listlist<char> lc_copy(++lc.begin(), --lc.end());for (const auto& k : li){cout << k << " ";}cout << endl;for (const auto& k : li_another){cout << k << " ";}cout << endl;for (const auto& k : lc){cout << k;}cout << endl;for (const auto& k : lc_copy){cout << k;}cout << endl;return 0;
}

【输出结果】


2.4 拷贝构造和赋值运算符重载 

【代码演示】

#include <iostream>
#include <list>
using namespace std;int main()
{//拷贝构造 list (const list& x)//赋值运算符重载 list& operator=(const list& x)list<int> li{ 1,2,3,4,5 };//拷贝构造list<int> li_copy(li);//赋值运算符重载list<int> li_another = li;for (const auto& k : li){cout << k << " ";}cout << endl;	for (const auto& k : li_copy){cout << k << " ";}cout << endl;for (const auto& k : li_another){cout << k << " ";}cout << endl;return 0;
}

【输出结果】 


三、迭代器

【示意图】

3.1 正向迭代器

【代码演示】

#include <iostream>
#include <list>
using namespace std;int main()
{list<int> li{ 1,2,3,4,5 };cout << *li.begin() << endl;cout << *(--li.end()) << endl;return 0;
}

        list的迭代器不能直接使用加法或减法(如+1或-1)来实现迭代器位置的更换,因为list的各个节点并不在一块连续的空间,如果直接通过加减法来实现迭代器位置的更换会造成非法访问。所以我们需要使用重载过后的前置或后置的加加、减减操作符来实现迭代器位置的变更。

 【输出结果】


3.2 反向迭代器

【代码演示】

#include <iostream>
#include <list>
using namespace std;int main()
{list<int> li{ 1,2,3,4,5,6,7 };list<int>::reverse_iterator rbit = li.rbegin();while (rbit != li.rend()){//从begin到end 从rbegin到rend都是++cout << *rbit << " ";++rbit;}cout << endl;return 0;
}

【输出结果】


四、容量相关 

4.1 获取list中有效数据的个数

【代码演示】

#include <iostream>
#include <list>
#include <string>
using namespace std;int main()
{list<string> ls{ "Hello", "lisr", "and", "string", "!" };cout << ls.size() << endl;return 0;
}

【输出结果】 


4.2 判断list是否为空 —— empty

【代码演示】

#include <iostream>
#include <list>
using namespace std;int main()
{list<int> li;cout << li.empty() << endl;//尾插一个1li.push_back(1);cout << li.empty() << endl;return 0;
}

【输出结果】


五、元素访问

5.1 获取第一个有效节点的数据

【代码演示】

#include <iostream>
#include <list>
using namespace std;int main()
{list<int> li{ 1,2,3,4,5,6 };cout << li.front() << endl;return 0;
}

【输出结果】


5.2 获取最后一个有效节点的数据

#include <iostream>
#include <list>
using namespace std;int main()
{list<string> ls{ "Hello", "list!" };cout << ls.back() << endl;return 0;
}

【输出结果】


六、修改相关

6.1 头插、尾插 —— push_front、push_back

【代码演示】

#include <iostream>
#include <list>
using namespace std;int main()
{list<int> li{ 2,3,4,5 };//头插1li.push_front(1);//尾插6li.push_back(6);for (const auto& k : li){cout << k << " ";}cout << endl;return 0;
}

【输出结果】


6.2 尾插、尾删 —— pop_front、pop_back 

【代码演示】

#include <iostream>
#include <list>
using namespace std;int main()
{list<int> li{ 1,2,3,4,5,6 };//头删li.pop_front();//尾删li.pop_back();for (const auto& k : li){cout << k << " ";}cout << endl;return 0;
}

【输出结果】


6.3 在任意位置插入

【代码演示】

#include <iostream>
#include <list>
using namespace std;int main()
{list<int> li{ 1,2,3,5,6,7 };list<int>::iterator pos = li.begin();//list的迭代器不支持直接加减一个值。//比如我们要在5的前面插入一个4,就必须让pos++3次,而不能pos + 3//循环的次数可以看成目标位置下标的数值,但不是真正的下标//因为list节点并不分布在一块连续的空间for (int i = 0; i < 3; ++i){++pos;}li.insert(pos, 4);for (const auto& k : li){cout << k << " ";}cout << endl;return 0;
}

【输出结果】

        list的插入操作不像vector的插入操作,在插入数据中如果进行了扩容,vector会发生迭代器失效,而list不会。这是因为vector的扩容是开辟一块更大的空间,将原空间数据拷贝到新空间后再释放原空间,而迭代器pos任然指向旧空间,这样就会对非法空间进行访问。但是list的扩容只是开辟一块空间来存储新的数据,其他数据的位置和关系并不会发生变化,所以并不会发生迭代器失效。


6.4 在任意位置删除 —— erase

#include <iostream>
#include <list>
using namespace std;int main()
{list<int> li{ 1,2,3,4,5,6,7,8 };list<int>::iterator pos = li.begin();//删除list中的所有偶数while (pos != li.end()){//避免发生迭代器失效if (*pos % 2 == 0){pos = li.erase(pos);}else{++pos;}}for (const auto& k : li){cout << k << " ";}cout << endl;return 0;
}

        虽然list在插入过程中不会发生迭代器失效,但是在删除过程中任然会发生迭代器失效。为了避免这种情况我们就需要利用erase的返回值

        erase的返回值是一个指向被删除数据的下一个数据的迭代器,我们在执行删除操作之后让迭代器pos等于erase的返回值,如果没有执行就正常++,这样就能避免迭代器失效问题了。


6.5 交换两个list对象

【代码演示】

#include <iostream>
#include <list>
using namespace std;int main()
{list<int> li1{ 1, 2, 3, 4 ,5 };list<int> li2{ 6, 7, 8 ,9, 10 };li1.swap(li2);cout << "li1的数据为:";for (const auto& k : li1){cout << k << " ";}cout << endl;cout << "li2的数据为:";for (const auto& k : li2){cout << k << " ";}cout << endl;return 0;
}

【输出结果】


6.6 清空list中的有效节点

【代码演示】

#include <iostream>
#include <list>
using namespace std;int main()
{list<int> li{ 1,2,3,4,5 };cout << "clear前的数据为:";for (const auto& k : li){cout << k << " ";}cout << endl;li.clear();cout << "clear后的数据为:";for (const auto& k : li){cout << k << " ";}cout << endl;return 0;
}

【输出结果】


七、链表操作

7.1 将一个list上的数据转移到另一个list —— splice

【函数原型】

【代码演示】

#include <iostream>
#include <list>
using namespace std;int main()
{list<int> des1{ 1,2,3,4,5 };list<int> des2(des1);list<int> des3 = des2;list<int> sour1{ 6,7,8,9,10 };list<int> sour2(sour1);list<int> sour3 = sour2;//转移一整个链表des1.splice(des1.end(), sour1);//转移一个元素des2.splice(des2.end(), sour2, sour2.begin());//转移一个区间 -》左闭右开des3.splice(des3.end(), sour3, ++sour3.begin(), --sour3.end());cout << "des1的数据为:";for (const auto& k : des1){cout << k << " ";}cout << endl;cout << "sour1的数据为:";for (const auto& k : sour1){cout << k << " ";}cout << endl;cout << "des2的数据为:";for (const auto& k : des2){cout << k << " ";}cout << endl;cout << "sour2的数据为:";for (const auto& k : sour2){cout << k << " ";}cout << endl;cout << "des3的数据为:";for (const auto& k : des3){cout << k << " ";}cout << endl;cout << "sour3的数据为:";for (const auto& k : sour3){cout << k << " ";}cout << endl;return 0;
}

【输出结果】


7.2 删除某个特定数据

【代码演示】

#include <iostream>
#include <list>
using namespace std;int main()
{list<int> li{ 1,2,3,1,1,5,8,5,4,3 };cout << "remove前的数据为:";for (const auto& k : li){cout << k << " ";}cout << endl;li.remove(1);cout << "remove后的数据为:";for (const auto& k : li){cout << k << " ";}cout << endl;return 0;
}

【输出结果】


7.3 给数据排序 —— sort

【代码演示】

#include <iostream>
#include <list>
using namespace std;int main()
{list<int> li{ 32,5,86,12,6,2 };//list排序通过归并排序实现li.sort();for (auto& k : li){cout << k << " ";}cout << endl;return 0;
}

【输出结果】

         注:list用不了algorithm算法库中的sort,因为algorithmsort的参数要求是随机迭代器RandomAccessIterator,而list的迭代器是双向迭代器bidirectional iterator

        除了随机迭代器RandomAccessIterator和双向迭代器bidirectional iterator外还有一种迭代器类型是InputIterator,这个迭代器类型就是只要是迭代器就行。

        不过话虽如此,但并不建议对list进行排序,因为list的数据在空间上是分散开的,并不适合排序,list排序的效率远远不及vector这种在连续空间上储存数据的容器,因此并不建议对list进行排序。


7.4 去除重复数据 —— unique

【代码演示】

#include <iostream>
#include <list>
using namespace std;int main()
{list<int> li{ 1,4,6,4,6,7,8,9,1,3,5 };//在去重之前建议先对list进行排序 不然效率实在是太低了 不过排序的效率也很低就是了li.sort();li.unique();for (const auto& k : li){cout << k << " ";}cout << endl;return 0;
}

【输出结果】


7.5 反转数据 —— reverse

【代码演示】

#include <iostream>
#include <list>
using namespace std;int main()
{list<int> li{ 1,2,3,4,5,6 };li.reverse();for (const auto& k : li){cout << k << " ";}cout << endl;return 0;
}

【输出结果】


八、list与vector的对比 

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/646538.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

android camera的使用以及输出的图像格式

一、Camera 1.1、结合SurfaceView实现预览 1.1.1、布局 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:app"http://schemas.android.com/apk/res-au…

burp靶场--CSRF

burp靶场–CSRF https://portswigger.net/web-security/csrf#what-is-csrf ### 什么是 CSRF&#xff1f; 跨站请求伪造&#xff08;也称为 CSRF&#xff09;是一种 Web 安全漏洞&#xff0c;允许攻击者诱导用户执行他们不打算执行的操作。它允许攻击者部分规避同源策略&#…

Unity 解决异步分发方案

很多程序&#xff0c;包括游戏、小程序、一些AR、VR的程序&#xff0c;因为客户端体量太大&#xff0c;更新频繁都涉及到远程热更新的问题&#xff0c;解决这类问题的思路基本上是客户端解决主要功能&#xff0c;资源类放置在服务器。 下面记录下&#xff1a; 1.CDN或者云轻量…

Windows11操作系统百科

简介 Windows 11是由微软公司&#xff08;Microsoft&#xff09;开发的操作系统&#xff0c;应用于计算机和平板电脑等设备 [1]。于2021年6月24日发布 [3]&#xff0c;2021年10月5日发行 [29]。 Windows 11提供了许多创新功能&#xff0c;增加了新版开始菜单和输入逻辑等 [6]…

安装ddddocr中遇到的问题

1、需要先安装&#xff1a; pip3 install pyinstaller --no-use-pep517 pip install scikit-build pip install setuptools pip install pyinstaller pip install pillow 重要是的是保证一个python 环境&#xff0c;多个python环境会导致各种问题。并且保证python>3.8…

安装宝塔面板后k8s所在节点pod无法正常工作解决方法,kubernetes k8s 与宝塔面板冲突解决方法

在实际项目过程中我们使用了k8s 在生产环境中运行管理服务。 但是对服务器的状态管理我们使用了宝塔面板进行 K8s 版本1.2.8 宝塔面板 版本 8.05 操作步骤是这样的。 1.完成1.2.8 k8s的节点安装&#xff0c;并正常运行服务。 过程略 2.安装宝塔面板 ​ yum install -y …

基于springboot留守儿童爱心网站源码和论文

随着留守儿童爱心管理的不断发展&#xff0c;留守儿童爱心网站在现实生活中的使用和普及&#xff0c;留守儿童爱心管理成为近年内出现的一个热门话题&#xff0c;并且能够成为大众广为认可和接受的行为和选择。设计留守儿童爱心网站的目的就是借助计算机让复杂的管理操作变简单…

Docker的Cgroup资源限制

目录 前瞻 CPU 资源控制 设置CPU使用率上限 设置CPU资源占用比&#xff08;设置多个容器时才有效&#xff09; 设置容器绑定指定的CPU 内存资源限制 对磁盘IO配额控制&#xff08;blkio&#xff09;的限制 前瞻 Docker 通过 Cgroup 来控制容器使用的资源配额&#xff0c…

让抖音引流到微信小程序的三方工具数灵通

抖音作为一款火爆的短视频社交平台&#xff0c;吸引了数亿用户的关注和喜爱。除了观看和制作视频外&#xff0c;抖音还提供了跳转到小程序的功能&#xff0c;让用户可以享受更多功能和乐趣。那么&#xff0c;如何在抖音中跳转到小程序呢&#xff1f;以下是详细解答&#xff1a;…

SpringBoot使用druid

SpringBoot使用druid 一、前言二、配置1、pom依赖2、配置文件yml3、配置类 一、前言 Java程序很大一部分要操作数据库&#xff0c;为了提高性能操作数据库的时候&#xff0c;又不得不使用数据库连接池。 Druid 是阿里巴巴开源平台上一个数据库连接池实现&#xff0c;结合了 C…

leetcode:排序链表(递归)

题目&#xff1a; 给定链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。 示例 1&#xff1a; 输入&#xff1a;head [4,2,1,3] 输出&#xff1a;[1,2,3,4]示例 2&#xff1a; 输入&#xff1a;head [-1,5,3,4,0] 输出&#xff1a;[-1,0,3,4,5]示例…

【华为 ICT HCIA eNSP 习题汇总】——题目集8

1、在VRP平台下&#xff0c;关于各个协议的外部优先级的描述&#xff0c;正确的是&#xff08;&#xff09;。 A、OSPF路由的外部优先级是15 B、IS-IS路由的外部优先级是10 C、静态路由的外部优先级是60 D、BGP路由的外部优先级是20 考点&#xff1a;路由技术原理 解析&#xf…

钉钉企业机器人单聊消息发送实践-大数据平台(XSailboat)消息中心消息推送

1. 背景 在笔者开发的大数据平台XSailboat中有 消息中心 模块&#xff0c;用来全平台的消息收集&#xff0c;整理分拆、订阅发送等功能。消息推送方式支持钉钉群聊、钉钉单聊、短信通知。现记录一下企业机器人消息单聊推送的实现过程。 2. 钉钉开发文档 这是官方的开发文档地…

MyBatis中一级缓存是什么?SqlSession一级缓存失效的原因?如何理解一级缓存?

一级缓存是SqlSession级别的&#xff0c;通过同一个SqlSession查询的数据会被缓存&#xff0c;下次查询相同的数据&#xff0c;就 会从缓存中直接获取&#xff0c;不会从数据库重新访问 使一级缓存失效的四种情况&#xff1a; 1) 不同的SqlSession对应不同的一级缓存 2) 同一…

好书推荐丨豆瓣评出9.2高分!Python编程入门就看蟒蛇书

目录 写在前面 内容简介 业内专家推荐 编辑推荐 资源丰富 作者介绍 Q&A 粉丝福利 写在后面 写在前面 在这日新月异的科技新时代&#xff0c;编程如同一把万能钥匙&#xff0c;为无数人打开了通向无限可能的大门。而在众多编程语言中&#xff0c;Python无疑是最耀…

etcd未授权到控制k8s集群

在安装完 K8s 后&#xff0c;默认会安装 etcd 组件&#xff0c;etcd 是一个高可用的 key-value 数据库&#xff0c;它为 k8s 集群提供底层数据存储&#xff0c;保存了整个集群的状态。大多数情形下&#xff0c;数据库中的内容没有加密&#xff0c;因此如果黑客拿下 etcd&#x…

防御课程—华为USG6000V1的配置实验(一)

实验拓扑&#xff1a; 实验分析 由实验拓扑图需求分析可知我们在生产区和办公区需要用到子接口技术 实验配置 在Cloud1上配置 在DMZ区域配置 在server1上配置在server2上配置在防火墙上进行的配置 由实验拓扑图可知防火墙与DMZ区域相连的接口为GigabitEthernet1/0/0接口 …

Pandas.Series.median() 中位数 详解 含代码 含测试数据集 随Pandas版本持续更新

关于Pandas版本&#xff1a; 本文基于 pandas2.2.0 编写。 关于本文内容更新&#xff1a; 随着pandas的stable版本更迭&#xff0c;本文持续更新&#xff0c;不断完善补充。 传送门&#xff1a; Pandas API参考目录 传送门&#xff1a; Pandas 版本更新及新特性 传送门&…

MySQL(基础篇)——SQL

一.SQL分类 二.DDL(数据定义语言) 1.DDL——数据库操作 ① 查询 查询所有数据库 SHOW DATABASES 查询当前所处数据库 SELECT DATABASE() ② 创建 CREATE DATABASE [IF NOT EXISTS] 数据库名(通常以db结尾) [DEFAULT CHARSET 字符集] [COLLATE 排序规则] ③ …

java分布式锁详解

本地锁 浏览器把100w请求由网关随机往下传&#xff0c;在集群情况下&#xff0c;每台服务都放行10w请求过来&#xff0c;这时候每台服务都用的是本地锁是跨JVM的&#xff0c; 列如这些服务都没有49企业&#xff0c;此时有几个服务进行回原了打击在DB上面&#xff0c;那后期把这…