【C++】list容器的基本使用

一、list是什么

list的底层结构是带头双向循环链表。

相较于 vector 的连续线性空间,list 就显得复杂很多,它是由一个个结点构成,每个结点申请的空间并不是连续的,它的好处是每次插入或删除一个数据,就配置或释放一个元素空间,我们不用在意扩容问题了,也不用单独写扩容函数了,list对于任何位置的元素进行插入或者元素移除,时间复杂度都是O(1)。

二、list容器的基本使用

1、构造函数

这里的allocator是空间配置器,我们这里先不用管它(认为它不存在),等到后面的篇章会具体讲解它的作用。 其中,(1)是默认构造 (2)是n个val构造 (3)是迭代器区间构造 (4)是拷贝构造。

2、析构函数

释放每个结点申请的空间资源。

3、赋值重载

它的操作数是两个已有的list对象。

4、迭代器

(1)使用

list的迭代器和vector的迭代器在用法上一模一样。

使用迭代器可以进行遍历:

#include <iostream>
#include <list>
using namespace std;void test_list1()
{list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(5);list<int>::iterator it = lt.begin();while (it != lt.end()){cout << *it << " ";++it;}cout << endl;
}int main()
{test_list1();return 0;
}

运行结果:

 

支持迭代器,就支持范围for,因为范围for的底层就是迭代器。

void test_list1()
{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;
}int main()
{test_list1();return 0;
}

运行结果:

 

(2)分类

迭代器从功能上进行分类,分为iterator、const_iterator、reverse_iterator、const_reverse_iterator这四类,它还可以从性质上进行分类,分为单向迭代器、双向迭代器、随机迭代器。

单向迭代器包括(forward):forward_list / unordered_map... 它只支持++

双向迭代器(bidirectional)包括:list / map / set... 它只支持++ / --

随机迭代器(random access)包括:vector / string / deque... 它支持++ / -- / + / -

它们的底层结构决定它们的性质,它们的底层结构也决定它们可以使用哪些算法。

比如:

C++标准库中sort的模板参数是RandomAccessIterator,从它的名字中可以看出它只接收随机迭代器,如果传一个单向迭代器,它也可以接收,但运行时会发生错误即程序不能正常运行。

C++标准库中reverse的模板参数是BidirectionalIterator,从它的名字中可以看出它只接收双向迭代器,如果传一个单向迭代器,它也可以接收,但运行时会发生错误即程序不能正常运行。如果传一个随机迭代器,也可以正常使用,因为随机迭代器的范围更广,凡是支持单向迭代器或者双向迭代器的都支持随即迭代器。

出现InputIterator,说明单向/双向/随机迭代器都可以使用这个函数。

5、成员函数

(1)empty()

判断容器内节点个数是否为空,若为空返回true,否则返回false。

(2)size()

返回容器内节点个数。

(3)front()

reference 就是list<T>中的T,T是模板参数。front就是用来返回第一个结点的值。

(4)back()

 返回最后一个结点的值。

(5)assign()

用于赋值。(1)是用一段迭代区间赋值 (2)是用n个val赋值

(6)push_front()

头插,头部插入一个新结点。

(7)pop_front()

头删,删除头部的结点。 

(8)push_back()

尾插,尾部插入一个新结点。

(9)pop_back()

尾删,删除尾部的结点。

(10)emplace_back()

它的功能和push_back()差不多,但有不同之处,现阶段我们就把它当作push_back()使用。

struct AA
{AA(int a1, int a2):_a1(a1), _a2(a2){}
private:int _a1;int _a2;
};void test_list2()
{list<AA> lt;AA aa1(1, 1);lt.push_back(aa1);lt.push_back(AA(2,2));//lt.push_back(3,3); //err,这里会报错lt.emplace_back(aa1);lt.emplace_back(AA(2,2));lt.emplace_back(3,3); //ok,与push_back()的不同之处,它支持直接传构造A对象的参数
}int main()
{test_list2();return 0;
}

(10)insert()

(1)是在pos位置前插入val (2)是在pos位置前插入n个val (3)是在pos位置前插入一段迭代区间。 

void test_list3()
{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;//在第3个位置前(整体位置是从0开始编号的)插入30//lt.insert(lt.begin() + 3, 30); //list容器不支持+,所以这行代码会报错list<int>::iterator it = lt.begin();int k = 3;while (k--){++it;//list容器支持++,所以这行代码会报错}lt.insert(it, 30);  //(1)for (auto e : lt)cout << e << " ";cout << endl;
}int main()
{test_list3();return 0;
}

运行结果: 

(11)erase()

 (1)删除pos位置上的值 (2)删除一段迭代区间

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(5);for (auto e : lt)cout << e << " ";cout << endl;int x;cin >> x;list<int>::iterator it = find(lt.begin(),lt.end(),x);if (it != lt.end()) //找到了lt.erase(it); //(1)elsecout << "不存在:" << x << endl;for (auto e : lt)cout << e << " ";cout << endl;}int main()
{test_list4();return 0;
}

输入4,运行结果: 

(12)clear()

清空所有结点数据。

(13)resize()

将结点个数更新到n,假设原先节点个数为k。

1、k > n

释放k - n个结点

2、k < n

增加n - k个节点,结点中的内容自己可以传,也可以不传,用默认的缺省值。

因为list的底层是链表,所以没有扩容这一说法。

(14)reverse()

逆置结点的顺序。

void test_list5()
{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;//reverse(lt.begin(),lt.end()); //这里的算法库中的reverse也支持list容器的逆置
}int main()
{test_list5();return 0;
}

运行结果:

 

(15)sort()

 由于算法库中的sort不支持list容器的迭代器,所以这里它自己实现了一个。

void test_list6()
{list<int> lt;lt.push_back(20);lt.push_back(40);lt.push_back(50);lt.push_back(30);lt.push_back(10);for (auto e : lt)cout << e << " ";cout << endl;//默认排升序lt.sort(); //(1)for (auto e : lt)cout << e << " ";cout << endl;}int main()
{test_list6();return 0;
}

运行结果: 

 

如果想要排降序,就要借助仿函数:

void test_list6()
{list<int> lt;lt.push_back(20);lt.push_back(40);lt.push_back(50);lt.push_back(30);lt.push_back(10);for (auto e : lt)cout << e << " ";cout << endl;//排降序greater<int> gt;lt.sort(gt);for (auto e : lt)cout << e << " ";cout << endl;}int main()
{test_list6();return 0;
}

运行结果:

 

(16)merge()

合并两个链表,前提是这两个链表需要有序。 

void test_list7()
{list<int> first, second;first.push_back(3);first.push_back(6);first.push_back(1);second.push_back(2);second.push_back(5);second.push_back(4);first.sort();second.sort();first.merge(second); //合并后,second这个链表就空了,相当于将它移到first上了for (auto e : first)cout << e << " ";cout << endl;cout << "----------" << endl;for (auto e : second) //second中已经没有数据了cout << e << " ";cout << endl;cout << "----------" << endl;
}int main()
{test_list7();return 0;
}

运行结果: 

 

 (17)unique()

去重,删除容器中与val值一样的结点,只保留第一个。删除时要保证重复的数据紧挨着,否则会删不干净,建议删除前先排序。

void test_list8()
{list<int> lt;lt.push_back(5);lt.push_back(1);lt.push_back(4);lt.push_back(2);lt.push_back(4);lt.push_back(3);lt.push_back(3);lt.push_back(5);for (auto e : lt)cout << e << " ";cout << endl;lt.sort();lt.unique();for (auto e : lt)cout << e << " ";cout << endl;
}int main()
{test_list8();return 0;
}

运行结果: 

(18)remove()

对val进行查找,如果找到就删除,否则什么也不做。 

(19)remove_if()

给定一个条件,如果满足就删除,否则什么也不做。

(20)splice()

 (1)是将x中全部结点转移到当前容器中的pos位置之前的位置处 (2)是将x中i位置的结点转移到当前容器中的pos位置之前的位置处 (3)是将x中的一段迭代区间上的结点转移到当前容器中的pos位置之前的位置处

//将一个链表的结点转移给另一个链表
void test_list9()
{list<int> mylist1, mylist2;list<int>::iterator it;//先插入一些值for (int i = 1; i <= 4; ++i)mylist1.push_back(i);      // mylist1: 1 2 3 4for (int i = 1; i <= 3; ++i)mylist2.push_back(i * 10);   // mylist2: 10 20 30cout << "初始值:" << endl;for (auto e : mylist1)cout << e << " ";cout << endl;for (auto e : mylist2)cout << e << " ";cout << endl;cout << "---------------" << endl;it = mylist1.begin();++it;                     mylist1.splice(it, mylist2); //(1)// mylist1: 1 10 20 30 2 3 4// mylist2中的数据已经没有了// "it" 仍然指向2 cout << "第一次调用splice后:" << endl;for (auto e : mylist1)cout << e << " ";cout << endl;for (auto e : mylist2)cout << e << " ";cout << endl;cout << "---------------" << endl;mylist2.splice(mylist2.begin(), mylist1, it); //(2)// mylist1: 1 10 20 30 3 4// mylist2: 2// "it"现在是无效的cout << "第二次调用splice后:" << endl;for (auto e : mylist1)cout << e << " ";cout << endl;for (auto e : mylist2)cout << e << " ";cout << endl;cout << "---------------" << endl;
}int main()
{test_list9();return 0;
}

运行结果: 

根据它的功能,我们还可以调整当前链表的结点顺序:

//调整当前链表结点的顺序
void test_list10()
{list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(5);lt.push_back(6);cout << "转移前:" << endl;for (auto e : lt)cout << e << " ";cout << endl;//现要求将6这个结点转移到1这个结点的前面去lt.splice(lt.begin(), lt, --lt.end());cout << "转移后:" << endl;for (auto e : lt)cout << e << " ";cout << endl;
}int main()
{test_list10();return 0;
}

三、排序效率

这里我们将list容器中的sort与算法库中的sort进行效率对比,看看哪个更优。

(1)对比一

#include <vector>
#include <iostream>
#include <algorithm>
#include <list>
using namespace std;void test_op1()
{srand((unsigned int)time(0));const int N = 1000000;list<int> lt1;vector<int> v;for (int i = 0;i < N;++i) //随机生成100万个数据{auto e = rand() + i;lt1.push_back(e);v.push_back(e);}int begin1 = clock();sort(v.begin(), v.end());int end1 = clock();int begin2 = clock();lt1.sort();int end2 = clock();cout << "vector sort:" << end1 - begin1 << endl;cout << "list sort:" << end2 - begin2 << endl;
}int main()
{test_op1();return 0;
}

在Debug环境下的运行结果:

可以看到list排序优势更大,那是因为在Debug环境下,优化不是很大,运行结果不具有参考价值,在release环境下,双方优化都是最大的,这才公平。

在Realse环境下运行结果:

实际上,算法库中的sort效率是更好的。 

(2)对比二

#include <vector>
#include <iostream>
#include <algorithm>
#include <list>
using namespace std;void test_op2()
{srand((unsigned int)time(0));const int N = 1000000;list<int> lt1;list<int> lt2;for (int i = 0;i < N;++i){auto e = rand() + i;lt1.push_back(e);lt2.push_back(e);}int begin1 = clock();vector<int> v(lt2.begin(), lt2.end()); //迭代器区间构造sort(v.begin(), v.end()); //用算法库中的sort进行排序lt2.assign(v.begin(), v.end()); //再拷贝回lt2int end1 = clock();int begin2 = clock();lt1.sort(); //直接调用list中的sort进行排序int end2 = clock();cout << "list copy vector sort copy list sort:" << end1 - begin1 << endl;cout << "list sort:" << end2 - begin2 << endl;
}int main()
{test_op2();return 0;
}

在Release环境下运行结果: 

这差距就出来了, 在begin1~end1这段时间内做的事情比begin2~end2这段时间内做的还要多,结果花费的时间还少,说明了当数据量比较大时,list中的sort排序效率很低。不如先把它的值拷贝给vector容器,然后排序,排完再拷贝回来。

四、结语

本篇内容到这里就结束了,主要讲了list容器的基本使用,希望对大家有些许收获,祝大家天天开心!

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

MATLAB绘图基础8:双变量图形绘制

参考书&#xff1a;《 M A T L A B {\rm MATLAB} MATLAB与学术图表绘制》(关东升)。 8.双变量图形绘制 8.1 散点图 散点图用于显示两个变量间的关系&#xff0c;每个数据点在图上表示为一个点&#xff0c;一个变量在 X {\rm X} X轴&#xff0c;一个变量在 Y {\rm Y} Y轴&#…

ACE搭建地图,助力企业新媒体矩阵优化升级

在数字化浪潮中&#xff0c;为了创造多元化的用户互动和销售机会&#xff0c;众多企业踊跃投入到线上平台&#xff0c;积极构建新媒体矩阵。 然而这条道路并非是坦途。很多对矩阵不了解或是认识不足的企业&#xff0c;想要搭建好矩阵还需要面临众多难题。 对新手来说&#xff0…

Qt 多线程TCP客户端使用QTimer进行重连服务器———附带详细代码和讲解

文章目录 0 背景1 原理1.1 QThread的线程归属1.2 Qtimer使用1.3 TCP客户端使用 2 问题解决2.1 解决思路2.2 解决方法 3 完整的代码示例3.1 tcp_client类3.2 主界面类 附录参考 0 背景 在子线程中&#xff0c;使用Qtimer来进行定时重连TCP服务器&#xff0c;总是会出现跨线程创…

如何通过思维链提升LLM推理能力?

思维链推理(Chain-of-Thought Reasoning)&#xff0c;因其彻底改变了模型处理复杂问题的解决方式&#xff0c;目前已成为人工智能领域最炙手可热的重大进展之一。 通过模拟推理过程&#xff0c;CoT训练大语言模型将复杂的问题拆解&#xff0c;并提供更清晰、更具逻辑的响应(re…

需求4:新加字段(进阶版)

关于加一个字段这种&#xff0c;我前几篇文章已经写过了。这篇文章的这个需求&#xff0c;也是写关于加字段的&#xff0c;只不过与前两篇文章不一样的是&#xff0c;这篇文章的这个需求讲的比较隐晦&#xff0c;需求没有直接跟你说要你加一个字段&#xff0c;要你自己想一下才…

(undone) 学习语音学中关于 i-vector 和 x-vector

来源&#xff1a;https://ieeexplore.ieee.org/stamp/stamp.jsp?tp&arnumber8461375 (这是一篇跟 X-vector 有关的论文) 这里有更适合初学者的两个资料: 1.https://www.youtube.com/watch?vR3rzN6JYm38 &#xff08;MIT教授的youtube视频&#xff09; 2.https://people.c…

【微信支付-服务商】SpringBoot集成微信服务商支付(多子商户集成)

SpringBoot集成微信服务商支付&#xff08;多子商户集成&#xff09; 前言一、前置工作1、获取商户平台的xxx核心参数2、关联对应的小程序&#xff08;appid&#xff09; 二、SpringBoot集成微信小程序1、引入pom依赖2、yml配置3、java代码文件3.1、Properties 配置类3.2 Confi…

基于JAVA+SpringBoot+Vue的学生干部管理系统

基于JAVASpringBootVue的学生干部管理系统 前言 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN[新星计划]导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末附源码下载链接&#x1f345; 哈…

windows打开可选功能窗口的方式(呜呜设置里面找不到可选功能只能这样找了)

打开方式 winR打开运行窗口&#xff0c;输入fodhelper&#xff0c;按下回车键 即可快速打开可选功能窗口

ChemChat——大语言模型与化学的未来,以及整合外部工具和聊天机器人的潜力

概述 论文地址&#xff1a;https://arxiv.org/abs/2309.16235 虽然近年来技术创新和变革日新月异&#xff0c;从根本上改变了我们对生物化学过程的认识&#xff0c;但化学领域仍花费大量时间和金钱–"10 年 "和 “3000 亿”–将新产品推向市场。这是由于实验室实验的…

发现编程的全新境界——明基RD280U显示器使用体验

前言 在大学的四年里&#xff0c;我几乎每天都泡在实验室&#xff0c;盯着电脑屏幕&#xff0c;一行行地码代码。那时&#xff0c;学校提供的显示器是非常基础的款式&#xff0c;功能简单&#xff0c;几乎没有任何特别之处&#xff0c;甚至配置也比较低。那个时候&#xff0c;…

Shader 中的光源

1、Shader 开发中常用的光源属性 Unity当中一共支持四种光源类型&#xff1a; 平行光&#xff08;Directional&#xff09;点光源&#xff08;Point&#xff09;聚光灯&#xff08;Spot&#xff09;面光源&#xff08;Area&#xff09;— 面光源仅在烘焙时有用 不管光源类型到…

通过MCGS在ARMxy边缘计算网关上实现物流自动化

随着电子商务和智能制造的快速发展&#xff0c;物流行业面临着前所未有的挑战与机遇。高效的物流系统不仅可以加快货物周转速度&#xff0c;降低运营成本&#xff0c;还能显著提升客户满意度。 1. ARMxy BL340系列简介 ARMxy BL340系列是针对工业自动化领域设计的一款高性能、…

2024年最新苹果cms升级插件【泛目录专用】

苹果CMS是一款专为视频内容管理而设计的系统&#xff0c;近年来在视频站点搭建中逐渐成为热门选择。其直观的用户界面和灵活的管理功能&#xff0c;使得无论是新手还是专业开发者都能轻松上手。 苹果CMS提供了多种主题和模板&#xff0c;用户可以根据自身需求进行定制&#xf…

北京买新能源车,天津上牌攻略

背景说明 我是在北京买的新能源汽车&#xff08;增程式&#xff09;&#xff0c;因没有摇上北京车牌号&#xff0c;所以计划在天津上牌。前期问了一些代理&#xff0c;要是帮忙弄的话得花500元左右&#xff0c;要是自己搞定的话&#xff0c;大约150元左右&#xff08;130元的车…

计算机毕业设计Spark+Hive旅游景点推荐 旅游推荐系统 景区游客满意度预测与优化 Apriori算法 景区客流量预测 旅游大数据 景点规划

流程&#xff1a; 1.DrissionPage自动化爬虫框架采集旅游数据约10万条存入mysql数据库、.csv文件作为数据集(旅游数据、用户数据、评论数据)&#xff1b; 2.使用pandasnumpy或MapReduce对数据进行数据清洗&#xff0c;生成最终的.csv文件并上传到hdfs(含nlp情感分析)&#xff1…

【每日刷题】Day127

【每日刷题】Day127 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 349. 两个数组的交集 - 力扣&#xff08;LeetCode&#xff09; 2. LCR 022. 环形链表 II - 力扣&a…

软设9.20

1 已知一个文件中出现的各字符及其对应的频率如下表所示。若采用定长编码&#xff0c;则该文件中字符的码长应为()。若采用Hufman编码&#xff0c;则字符序列“face”的编码应为()。 1.&#xff08;&#xff09; A.2 B.3 C.4 D.5 2.&#xff08;&#xff09; A.110001001101…

工程师 - PFM介绍

在电子电路设计中&#xff0c;PFM&#xff08;Pulse Frequency Modulation&#xff0c;脉冲频率调制&#xff09;是一种调制技术&#xff0c;其主要特点是在负载变化时调整脉冲的频率&#xff0c;而保持脉冲的宽度&#xff08;时间长度&#xff09;相对恒定。与PWM&#xff08;…

详解Vue事件总线的原理与应用:EventBus

Vue 事件总线 - 组件通信的桥梁 引言 在 Vue.js 开发中&#xff0c;组件通信是一个重要的话题。Vue 提供了多种方式来实现不同组件之间的通信&#xff0c;譬如Props、 $emit、Ref实例、Vuex状态管理及事件总线等等&#xff0c;可谓是五花八门&#xff0c;它们之间使用各有优缺…