【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…

vue2面试题:vue组件之间的通信方式有哪些?

vue2面试题&#xff1a;vue组件之间的通信方式有哪些&#xff1f; 回答思路&#xff1a;1.组件通信的目的-->2.组件通信的分类-->3.组件通信的方案1.组件通信的目的2.组件通信的分类3.组件通信的方案&#xff08;1&#xff09;通过props传递数据&#xff08;2&#xff09…

安装宝塔面板后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;…

Mysql 数据库(一)

Mysql 数据库 目录名作用bin可执行文件&#xff0c;存放就是命令及工具data不一定在主目录&#xff0c;是可以自定义配置&#xff08;my.ini&#xff09;。存放数据的&#xff0c;表结构&#xff0c;表数据docsmysql相关指导文件include包含头文件&#xff0c;提供程序的连接及…

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]示例…

node多版本管理使用npm失败的方法

问题 npm install 报错 解决 首先找到nvm安装的node路径和nodejs的路径&#xff08;这两文件最好在C盘的统一目录下&#xff0c;不是C盘会存在权限问题&#xff09; nodejs的路径:C:\soft\nodejs nvm的路径&#xff1a;C:\soft\nvm 因为我之前是安装在D盘的&#xff0c;np…

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

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

程序员的未来-大环境和技术变革

#程序员裁员潮&#xff1a;技术变革下的职业危机# 本来不太想写这一类的话题&#xff0c;但是吧&#xff0c;希望自己的一些经验、历程和观点&#xff0c;对现在的年轻人有一些启发。 经济环境 这个话题其实很沉重&#xff0c;好像有很多话要说&#xff0c;但是&#xff0c;…

钉钉企业机器人单聊消息发送实践-大数据平台(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无疑是最耀…