C++STL详解(五)——list类的接口详解

一.list的介绍

list容器的底层是双向循环带头链表,在CPP中,我们对双向循环带头链表进行了一定程度的封装。

如果你不了解双向链表,那么可以浏览此片博文:双向链表

二.list的定义方式以及赋值

2.1list的构造方式

在这里我们要学习六种list的构造方式。

构造1:构造一个某类型容器

list<int> list1;

构造2:构造一个含有一个值的某类型容器

list<int> list2(3);//构造只含有一个数值3的结点的list容器

构造3:构造一个含有n个值的某类型容器

list<int> list3(3, 5);//构造含有三个数值都是5的结点的list容器

构造4:复制某个容器构造该容器的复制品

list<int> list4(list3);//拷贝构造

构造5:使用某个迭代器区间进行构造

list<int> list5(list3.begin(), list3.end());//迭代器区间初始化

 构造6:使用列表构造一个某类型容器

	list<int> list6{ 1,2,3,4,5,6 };//使用列表构造

 2.2operator=重载函数

同样的,我们也可以使用重载后的operator=操作符来进行给一个空的list容器赋值。

方式1:将别的同类型容器赋值给该容器

list<int> list7 = list5;

方式2:使用列表

list<int> list8 = { 1,2,3,4,5,6 };

三.list的插入和删除

list库中提供给我们大家的需要我们学习的函数是头插和尾插函数以及头删和尾删函数。

下面我们逐个进行学习。

3.1push_front和pop_front

我们可以通过这两个函数进行头插和头删。

函数原型如下:

	void push_front(const value_type& val);void pop_front();

 我们可以使用这两个函数对list的头部进行删除和插入操作。

如下:

void test2()
{list<int> list1;list1.push_front(3);list1.push_front(4);list1.push_front(5);list1.push_front(6);print(list1);//为了方便写博客,这个是自己写的函数。list1.pop_front();print(list1);
}

结果: 

6 5 4 3
5 4 3

3.2push_back和pop_back

 我们可以通过这两个函数进行尾插和尾删。

函数原型如下:

	void push_back(const value_type& val);void pop_back();

 我们可以使用这两个函数对list的尾部进行删除和插入操作。

void test2()
{list<int> list2;list2.push_back(1);list2.push_back(2);list2.push_back(3);list2.push_back(4);print(list2);list2.pop_back();print(list2);
}

 结果:

1 2 3 4
1 2 3

3.3insert

insert函数用于在指定位置插入数据。 

insert函数的函数原型如下:

iterator insert(iterator position, const value_type& val);//在pos位置插入一个val
void insert(iterator position, size_type n, const value_type& val);//在position位置插入n个val
void insert(iterator position, InputIterator first, InputIterator last);//在position位置插入[first,last)区间的内容。

insert:

  • 函数1:在position位置插入一个val
  • 函数2:在position位置插入n个val
  • 函数3:在position位置插入迭代器区间[first,last)中的内容。
void test3()
{list<int> l1(3, 1);l1.insert(l1.begin(), 2);print(l1);l1.insert(l1.begin(), 3,3);print(l1);list<int> l2{ 3,2,1 };l1.insert(l1.begin(), l2.begin(),l2.end());print(l1);
}

结果: 

2 1 1 1
3 3 3 2 1 1 1
3 2 1 3 3 3 2 1 1 1

3.4erase

 erase函数用于在指定位置删除数据。 

erase函数的函数原型如下:

iterator erase(iterator position);
iterator erase(iterator first, iterator last);

erase:

  • 函数1:删除position位置的数据。
  • 函数2:删除迭代区间[first,last)中的数据。 
void test3()
{list<int> l1(3, 1);l1.insert(l1.begin(), 2);l1.insert(l1.begin(), 3,3);list<int> l2{ 3,2,1 };l1.insert(l1.begin(), l2.begin(),l2.end());l1.erase(l1.begin());print(l1);l1.erase(++l1.begin(), --l1.end());//注意是前置++和--,而不是后置的++--print(l1);
}

结果:

2 1 3 3 3 2 1 1 1
2 1

四.list的迭代器使用

list和别的容器不同的地方在于:list的迭代器只支持++和--,不支持+和-。

因此,下面的操作是不合法的:

	list<int>::iterator it = find(3, l1.begin(), l1.end());it + 1;

4.1begin和end

begin()end()是list的正向迭代器函数

  • begin()函数返回list容器的第一个位置
  • end()函数返回list容器的最后一个位置的下一个位置

图解如下:

4.2rbegin和rend

rbegin()rend()是list的反向迭代器函数 

  • rbegin()函数返回vector容器的最后一个位置
  • rend()函数返回vector容器的第一个位置的前一个位置

图解如下: 

同样的,我们可以使用以上的两种迭代器对list内的元素进行遍历。

如下:

void test4()
{list<int> l1{ 1,2,3,4 };//正向迭代器list<int>::iterator it1 = l1.begin();while (it1 != l1.end()){cout << *it1 << ' ';it1++;}cout << endl;//反向迭代器list<int>::reverse_iterator it2 = l1.rbegin();while (it2 != l1.rend()){cout << *it2 << ' ';it2++;}cout << endl;
}

结果: 

1 2 3 4
4 3 2 1

五.list的元素获取

5.1front和back

front用于获取头部元素,back用于获取尾部元素。

这两个函数比较简单,我们使用一下即可。

void test5()
{list<int> l1{ 1,2,3,4 };cout << l1.front() << endl;cout << l1.back() << endl;
}

结果:

1

4

六.list的空间控制

6.1size

我们在初始化一个list容器之后,可以通过这个函数查看该容器的有效数据个数。

函数原型如下:

void size();

在我们用两个1初始化一个list容器之后,可以使用这个函数查看它的有效数据个数。 

6.2resize

使用这个函数可以重设函数的有效数据。

函数原型如下:

void resize(size_type n, value_type val = value_type());

resize:

  • 如果有效数据个数大于当前size,若规定了特定值则用特定值填充,否则用数据类型的默认值填充
  • 如果有效数据个数小于当前size,则只保留前size个数据。
void test6()
{list<int> l1(2, 1);cout << l1.size() << endl;l1.resize(5);print(l1);//1 1 0 0 0 l1.resize(10, 1); print(l1);//1 1 0 0 0 1 1 1 1 1l1.resize(3);print(l1);//1 1 0
}

6.3empty

empty函数判断list容器是否为空的函数。

empty:

  • 如果vector容器为空,则返回真
  • 如果vector容器不为空,则返回假。
	list<int> l1(2, 1);list<int> l2;cout << l1.empty() << endl;//0-->假cout << l2.empty() << endl;//1-->真

6.4clear

clear函数用于清除list容器中的数据并置size为0.

clear:

  • 清除掉list容器内所有的元素,并将size置为0
list<int> l1(2, 1);
cout << l1.empty() << endl;//0-->假
l1.clear();
cout << l1.empty() << endl;//1-->真

6.5assign

assign函数用于将新内容分配给容器,替换其当前内容。

assign函数原型如下:

	void assign(InputIterator first, InputIterator last);void assign(size_type n, const value_type & val);

assign: 

  • 函数2:将所给迭代器区间当中的内容分配给容器。
  • 函数1:将n个值为val的数据分配给容器。
void test13()
{list<int> l1(3, 1);list<int> l2(3,2);print(l1);//1 1 1l1.assign(5, 2);print(l1);///2 2 2 2 2l1.assign(l2.begin(), l2.end());print(l1);//2 2 2
}

结果:

1 1 1
2 2 2 2 2
2 2 2

 

七.list的操作相关函数

7.1sort

sort函数是用于升序排列list内的元素的。

函数原型如下:

void sort();

sort:

  • 将list内的元素默认排为升序。 
void test7()
{list<int> l1{ 10,9,8,7,6,5,4,3,2,1 };print(l1);//10 9 8 7 6 5 4 3 2 1l1.sort();print(l1);//1 2 3 4 5 6 7 8 9 10
}

结果:

10 9 8 7 6 5 4 3 2 1
1 2 3 4 5 6 7 8 9 10

7.2splice

splice的功能类似于vector的insert函数,它可以用于在指定位置将另一个list容器插入。

但是,这个和insert函数不同的是,splice函数本质是一种转移,而不是复制。

splice的函数原型如下:

void splice(iterator position, list& x);
void splice(iterator position, list& x, iterator i);
void splice(iterator position, list& x, iterator first, iterator last);

splice:

  • 函数1:在position位置转移x容器的所有元素
  • 函数2:在position位置转移xi位置的元素
  • 函数3:   在position位置转移x的[first,last)区间内的元素。
void test8()
{list<int> l1{ 5,4,3,2,1 };list<int> l2{ 6,7,8,9,10 };list<int> l3{ 0,11,12,13 };list<int> l4{ 0,11,12,13 };l1.splice(l1.end(), l2);print(l1);//5 4 3 2 1 6 7 8 9 10l1.splice(l1.end(), l3,++l3.begin());print(l1);//5 4 3 2 1 6 7 8 9 10 11 print(l3);//0 12 13l3.splice(l3.begin(), l4,++l4.begin(),--l4.end());print(l3);//11 12 0 11 12print(l4);//0 13
}

 结果:

5 4 3 2 1 6 7 8 9 10
5 4 3 2 1 6 7 8 9 10 11
0 12 13
11 12 0 12 13
0 13
 

这里需要大家注意的是,splice函数的本质是转移!

现在我通过画图的形式来解析这段代码:

四个容器:

第一次转移:

第二次转移:

第三次转移:

7.3remove

remove函数是用来删除list容器内的值的。

函数原型如下:

void remove (const value_type& val);

remove:

  • remove函数可以删除掉容器内所有值是val的结点 
void test9()
{list<int> l1{ 5,4,4,3,2,1 };print(l1);//5 4 4 3 2 1l1.remove(4);print(l1);//5 3 2 1
}

 结果:

5 4 4 3 2 1
5 3 2 1

7.4unique

这个函数是用来去除相同的元素的。

它会拿当前的元素和下一个元素进行比较,如果和下一个元素相同的话,则删掉下一个元素。

因为它的这个特性,我们常用于有序列表的去重。

函数原型如下:

void unique();

我们可以通过下面这段代码体会到这个函数的性质:相邻比较,相等删除。 

void test10()
{list<int> l1{ 1,1,3,3,4,1 };l1.unique();print(l1);//1 3 4 1
}

结果:

1 3 4 1 

7.5merge

merge函数用于合并两个有序list容器。

merge函数的原型如下:

 void merge (list& x);

merge:

  • merge函数用于合并两个有序的list容器,合并后的list容器依旧有序。
  • 作为参数被传递的容器被合并后会为空
void test11()
{list<int> l1{1,3,5,7,9};list<int> l2{2,4,6,8,10};l1.merge(l2);print(l1);//1 2 3 4 5 6 7 8 9 10print(l2);//
}

结果:

1 2 3 4 5 6 7 8 9 10

 7.6reverse

reverse用于翻转链表。

函数原型如下: 

void reverse();
void test12()
{list<int> l1{ 1,3,5,7,9 };l1.reverse();print(l1);
}

结果:

9 7 5 3 1 

7.7swap

swap函数用于交换两个容器的内容。

void test14()
{list<int> l1(3, 1);list<int> l2(3, 2);l1.swap(l2);print(l1);//2 2 2print(l2);//1 1 1
}

结果:

2 2 2
1 1 1 

八.list的迭代器失效问题

在之前的文章中提过这个问题,此处大家可将迭代器暂时理解成类似于指针,迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。因为list的底层结构为带头结点的双向循环链表,而双向循环链表的扩容和顺序表不同,是不会出现异地扩容的现象的。因此在list中进行插入时是不会导致list的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。

下面的这段代码就是非常典型的一段迭代器失效的代码: 

void test15()
{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时,必须先给其赋值l.erase(it);++it;}
}

和vector一样,我们在使用前给迭代器赋值即可。

void test15()
{int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };list<int> l(array, array + sizeof(array) / sizeof(array[0]));list<int>::iterator it = l.begin();while (it != l.end()){it=l.erase(it);++it;//这行代码和上面两行代码等效//l.erase(it++)}
}

九.后记

有关list的模拟实现可参考博主的下篇博文。

如果你想更深入的了解list的相关内容,可参考cpp官网:cpp官网

码字不易,给个点赞收藏叭~~~

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

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

相关文章

idea中如何创建yml、yaml、properties配置文件

目录 1、配置文件 2、创建yml配置文件 3、配置文件的优先级 1、配置文件 我们一直使用springboot项目创建完毕后自带的application.properties进行属性的配置&#xff0c;那其实呢&#xff0c;在springboot项目当中是支持多种配置方式的&#xff0c;除了支持properties配置文件…

华为od机试真题:考勤信息(Python)

题目描述 公司用一个字符串来表示员工的出勤信息 absent:缺勒late: 迟到leaveearly: 早退present: 正常上班 现需根据员工出勤信息&#xff0c;判断本次是否能获得出勤奖&#xff0c;能获得出勤奖的条件如下: 缺勤不超过一次&#xff0c;没有连续的迟到/早退:任意连续7次考…

计算机二级刷题(讲+练)

【拯救者】二级C语言历届真题解析(二级期末升本均适用) 前提: 学过C语言, 想要速成可以看我的C语言课程 3套真题 赠送1套预测题(带解析)

【SOC 芯片设计 DFT 学习专栏 -- DFT DRC规则检查】

请阅读【嵌入式及芯片开发学必备专栏】 请阅读【芯片设计 DFT 学习系列 】 如有侵权&#xff0c;请联系删除 转自&#xff1a; 芯爵ChipLord 2024年07月10日 12:00 浙江 文章目录 概述DRC的概念Tessent DRC检查的概述时钟相关检查扫描相关检查BIST规则检查预DFT时钟规则检查 …

基于Vue开发的前端系统中寻找后端API及其参数

前言 在日常渗透工作中&#xff0c;常常遇到后台系统&#xff0c;且有相当一部分是自研开发的系统&#xff0c;没有源代码&#xff0c;没有弱口令漏洞&#xff0c;也没有swagger、webpack泄露等。幸运的是&#xff0c;这些系统几乎都是前后端分离的架构&#xff0c;而我发现使…

【OpenCV C++20 学习笔记】调节图片对比度和亮度(像素变换)

调节图片对比度和亮度&#xff08;像素变换&#xff09; 原理像素变换亮度和对比度调整 代码实现更简便的方法结果展示 γ \gamma γ校正及其实操案例线性变换的缺点 γ \gamma γ校正低曝光图片矫正案例代码实现 原理 关于OpenCV的配置和基础用法&#xff0c;请参阅本专栏的其…

视频号矩阵系统,AI自动生成文案,实现批量上传视频和定时发布

在数字化浪潮席卷全球的今天&#xff0c;视频内容已成为信息传播的重要载体。然而&#xff0c;对于众多自媒体创作者和企业而言&#xff0c;如何高效、精准地发布视频内容&#xff0c;依然是一个不小的挑战。幸运的是&#xff0c;随着技术的不断进步&#xff0c;视频号矩阵系统…

0725,进程间传递文件描述符,socketpair + sendmsg/recvmsg

我要碎掉了我要碎掉了我要碎掉了 上课喵&#xff1a; pipe匿名管道的问题 #include <func.h>int main() {int fds[2];pipe(fds);pid_t pidfork();if(pid>0){ //fatherclose(fds[0]);//close readint fdopen("file2.txt",O_RDONLY);printf("father: …

Idea2024 创建Meaven项目没有src文件夹

1、直接创建 新建maven项目&#xff0c;发现没有src/main/java 直接新建文件夹&#xff1a;右击项目名->new->Directory 可以看到idea给出了快捷创建文件夹的选项&#xff0c;可以根据需要创建&#xff0c;这里点击src/main/java 回车&#xff0c;可以看到文件夹已经创建…

用户管理与高级SQL语句(数据库管理与高可用)

1.表&#xff08;Table &#xff09; 数据库中的表与我们日常生活中使用的表格类似&#xff0c;它也是由行&#xff08;Row&#xff09; 和列&#xff08;Column&#xff09;组成的。列由同类的信息组成&#xff0c;每列又称为一个字段&#xff0c;每列的标题称为字段名。行包…

sql注入的专项练习 sqlilabs(含代码审计)

在做题之前先复习了数据库的增删改查&#xff0c;然后自己用本地的环境&#xff0c;在自己建的库里面进行了sql语句的测试&#xff0c;主要是回顾了一下sql注入联合注入查询的语句和sql注入的一般做题步骤。 1.获取当前数据库 2.获取数据库中的表 3.获取表中的字段名 一、sql…

51单片机嵌入式开发:19、STC89C52R控制LCD1602码表+数码管+后台数显(串口)

STC89C52R控制LCD1602码表数码管后台数显&#xff08;串口&#xff09; 1 概述1.1 项目概述1.2 项目组成部分1.3 功能描述 2 开发环境2.1 支持设备2.2 硬件电路 3 软件代码工程4 演示4.1 Proteus仿真4.2 实物演示 5 总结 1 概述 1.1 项目概述 本项目旨在利用STC89C52R单片机实…

联通智慧商业零售解决方案,旨在为全球零售企业提供低成本、高效能的组网与通信服务

联通智慧商业零售解决方案&#xff1a;驱动零售业全球布局与创新 在全球化的大背景下&#xff0c;零售业面临着前所未有的机遇与挑战。随着消费者需求的多样化和市场环境的快速变化&#xff0c;零售商必须不断寻求创新&#xff0c;以保持竞争力。中国联通国际&#xff0c;凭借…

优略解距离法—Topsis模型【清风数模学习笔记】

层次分析法的局限性 &#xff08;1&#xff09;决策层不能太多 &#xff08;2&#xff09;数据已知&#xff0c;使用层次分析法不准确 构造计算评分 相较于取卷面理论上的最高分&#xff08;100&#xff09;和最低分&#xff08;0&#xff09;&#xff0c;取分数区间上的最…

Golang | Leetcode Golang题解之第290题单词规律

题目&#xff1a; 题解&#xff1a; func wordPattern(pattern string, s string) bool {word2ch : map[string]byte{}ch2word : map[byte]string{}words : strings.Split(s, " ")if len(pattern) ! len(words) {return false}for i, word : range words {ch : patt…

CSS技巧专栏:一日一例 12 -纯CSS实现边框上下交错的按钮特效

CSS技巧专栏&#xff1a;一日一例 12 -纯CSS实现边框上下交错的按钮特效 大家好&#xff0c;今天我们来做一个上下边框交错闪动的按钮特效。 本例图片 案例分析 虽说这按钮给人的感觉就是上下两个边框交错变换了位置&#xff0c;但我们都知道border是没法移动的。那么这个按…

python实现接缝雕刻算法

python实现接缝雕刻算法 接缝雕刻算法步骤详解Python实现详细解释优缺点应用领域接缝雕刻算法(Seam Carving Algorithm)是一种内容感知的图像缩放技术,可以智能地改变图像的尺寸,而不会明显影响其重要内容。它通过动态规划的方式寻找图像中的“接缝”,即在图像中从上到下或…

排序系列 之 希尔排序

&#xff01;&#xff01;&#xff01;排序仅针对于数组哦本次排序是按照升序来的哦 介绍 英文名为ShellSort&#xff0c;又称“缩小增量排序”是直接插入排序算法的一种更高效的改进版本希尔排序是把记录按下标的指定步长分组&#xff0c;然后按照每组使用直接插入排序&#…

【全面讲解下Docker in Docker的原理与实践】

🌈个人主页: 程序员不想敲代码啊 🏆CSDN优质创作者,CSDN实力新星,CSDN博客专家 👍点赞⭐评论⭐收藏 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共同学习、交流进步! 👉目录 👉前言👉原理👉实践👉安全和最佳实践👉前言 🦛…

Python 教程(三):字符串特性大全

目录 专栏列表前言1. 字符串基础2. 字符串方法字符串查询字符串修改字符串切片 3. 字符串格式化旧式格式化&#xff08;% 操作符&#xff09;str.format() 方法f-string&#xff08;Python 3.6&#xff09; 4. 字符串编码5. Unicode 和 ASCII6. 正则表达式7. 字符串比较8. 字符…