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

news2024/11/16 6:23:46

一.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 1
	l1.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 1
	l1.assign(5, 2);
	print(l1);///2 2 2 2 2
	l1.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 1
	l1.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 10
	l1.splice(l1.end(), l3,++l3.begin());
	print(l1);//5 4 3 2 1 6 7 8 9 10 11 
	print(l3);//0 12 13
	l3.splice(l3.begin(), l4,++l4.begin(),--l4.end());
	print(l3);//11 12 0 11 12
	print(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 1
	l1.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 10
	print(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 2
	print(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://www.coloradmin.cn/o/1956488.html

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

相关文章

Redis:事务

1. 简介 可以一次性执行多个命令&#xff0c;本质是一组命令的集合。一个事务中的所有命令都会序列化&#xff0c;按顺序的串化执行&#xff0c;不允许被其他其他命令插入&#xff0c;不许加塞 即将要执行的命令放入队列中&#xff0c;此时该队列的所有命令就是一个事务&#x…

接口自动化中对于文件上传的处理方法

正常的接口自动化基本都是json的格式&#xff0c;对于文件上传是一种特殊的格式是表单格式针对这种表单格式在接口自动化中怎么处理&#xff0c;主要通过工作中使用的一个实际的例子进行分享 举例&#xff1a;web上需要导入一个文件实现相关的功能&#xff0c;主要通过两个接口…

vue实现滚动条下滑时隐藏导航栏,上滑时显示导航栏

效果展示 思路 监听滚动事件&#xff0c;记录上次的滚动距离&#xff0c;与最新滚动距离做对比&#xff0c;如果为正&#xff0c;说明滚动距离距顶值scrollTop变大&#xff0c;用户正在向下滚动页面&#xff0c;此时隐藏&#xff0c;反之则反&#xff0c;隐藏就是top值给他负导…

Linux网络-netstat命令

作者介绍&#xff1a;简历上没有一个精通的运维工程师。希望大家多多关注我&#xff0c;我尽量把自己会的都分享给大家&#xff0c;下面的思维导图也是预计更新的内容和当前进度(不定时更新)。 Linux服务器作为一个常用的网络服务器&#xff0c;主要的作用就是向客户端提供网络…

地球磁场的形成、变迁、特点

还是大剑师兰特&#xff1a;曾是美国某知名大学计算机专业研究生&#xff0c;现为航空航海领域高级前端工程师&#xff1b;CSDN知名博主&#xff0c;GIS领域优质创作者&#xff0c;深耕openlayers、leaflet、mapbox、cesium&#xff0c;canvas&#xff0c;webgl&#xff0c;ech…

Python如何统治AI世界?一文读懂它的优势与挑战

一、Python语言介绍 1.1 Python语言概述 Python是一种由Guido van Rossum于1991年首次发布的高级编程语言。其设计理念强调代码的可读性和简洁性&#xff0c;使其成为了许多开发者的首选语言。Python的语法简洁直观&#xff0c;采用了缩进来定义代码块&#xff0c;这与其他使…

应力对薄膜有什么影响?

知识星球里的学员问&#xff1a;在薄膜沉积中&#xff0c;应力是一个经常要监控的参数&#xff0c;它有什么作用&#xff1f;应力过大对薄膜有哪些影响&#xff1f; 应力是什么&#xff1f; 薄膜的应力是指在薄膜沉积过程中&#xff0c;薄膜内部或薄膜与基材之间产生的作用力。…

3Dtiles文件是否可以直接合并?

答&#xff1a;无法直接合并。网格大师有3dtiles转osgb的功能&#xff0c;先转osgb&#xff0c;然后把osgb放在一起之后再转3dtiles。 网格大师是一款能够解决实景三维模型空间参考、原点、瓦块大小不统一&#xff0c;重叠区域处理问题的工具“百宝箱”&#xff0c;集格式转换…

大数据:数据标准化及质量管控方案

本方案是一套全面的解决方案&#xff0c;旨在为企业构建科学、规范的数据管理体系&#xff0c;确保数据的准确性、一致性、完整性、合理性、及时性和有效性&#xff0c;从而支撑业务数据的高效应用与正确决策。以下是对该方案的详细介绍&#xff1a; 一、方案概述 本数据标准…

Redis八股文(二)

目录 21.Redis如何实现服务高可用&#xff1f; 22.什么是集群中的脑裂&#xff1f; 23.脑裂导致数据丢失怎么办&#xff1f; 24.Redis使用的过期删除策略是什么&#xff1f; 25.什么是惰性删除&#xff1f; 26.什么是定期删除&#xff1f; 27.Redis持久化时&#xff0…

超级详细的SpringSecurity

文章目录 概述与shiro对比快速入门底层原理FilterDelegatingFilterProxyFilterChainProxySecurityFilterChainMultiple SecurityFilterChain 自定义登录流程解析基于内存的用户认证实现基于数据库的用户登录 实现用户新增功能controllerservice修改配置关闭csrf攻击防御修改默认…

python拼接字符串方法

文章目录 1. 使用加号&#xff08;&#xff09;2. 使用str.join()方法3. 使用格式化字符串&#xff08;f-strings, % 操作符, .format() 方法&#xff09;4. 使用列表推导式和join()结合 性能对比 在Python中&#xff0c;字符串拼接是将两个或多个字符串合并成一个新字符串的过…

C++初学(3)

面向对象编程&#xff08;OOP&#xff09;的本质是设计并拓展自己的数据类型&#xff0c;设计自己的数据类型就是让类型与数据匹配。内置的C类型分为两组&#xff1a;基本类型和复合类型。这里我们将介绍基本类型的整数和浮点数 3.1、简单变量 3.1.1、变量名 C必须遵循几种简…

理解常见开源协议的区别

本文将介绍几种常见的开源许可证&#xff0c;包括GPL、LGPL、MIT、Apache、BSD 和 木兰协议&#xff08;Mulan PSL&#xff09;&#xff0c;并详细解释它们的区别。 1. GPL (GNU General Public License) GPL 是最著名和最常用的开源许可证之一&#xff0c;由自由软件基金会 …

【前端 17】使用Axios发送异步请求

Axios 简介与使用&#xff1a;简化 HTTP 请求 在现代 web 开发中&#xff0c;发送 HTTP 请求是一项常见且核心的任务。Axios 是一个基于 Promise 的 HTTP 客户端&#xff0c;适用于 node.js 和浏览器&#xff0c;它提供了一种简单的方法来发送各种 HTTP 请求。本文将介绍 Axio…

如何在 Excel 中恢复临时文件

如果您在退出 Microsoft Excel 之前忘记保存重要的工作簿&#xff0c;这会令人烦恼和头疼。此外&#xff0c;在某些意外情况下&#xff0c;包括计算机突然崩溃、软件本身崩溃等&#xff0c;您精心制作的工作簿可能会消失。但是&#xff0c;您仍然可以使用Excel 临时服务恢复 Ex…

中山大学与Pixocial联手提出CatVTON:轻量化架构与高效训练,助力虚拟试衣技术落地应用!

近日&#xff0c;中山大学和 Pixocial 联合发布了 CatVTON&#xff0c;提出更加轻量化的架构与参数高效训练策略&#xff0c;助力图像虚拟试衣技术向落地应用迈进&#xff01; 项目已公开论文并开源权重和代码&#xff0c;更有在线 Demo 可以试玩&#xff01; 给钢铁侠穿上奇异…

Qt Creator初识

目录 一、认识 Qt Creator 1.Qt Creator 概览 2.使用 Qt Creator 新建项目 2.1 新建项目 2.2 选择项目模板 2.3 选择项目路径 2.4 选择构建系统 2.5 填写类信息设置界面 2.6 选择语言和翻译文件 2.7 选择 Qt 套件 2.8 选择版本控制系统 2.9 最终效果 3.认识 Qt Cre…

【详细】Ubuntu下安装qt5

Ubuntu下安装qt5 一. QT安装环境准备1、判断gcc是否安装2、安装g3、安装clang编译器4、安装 clang 5、安装make6、安装make-guile7、安装cmake 二. QT5安装1、安装Qt5的组件2、安装Qt的开发工具3、安装qtcreator4、安装qt55、安装qt charts&#xff08;可选&#xff09; 三、安…

VS2022创建C C++ GTEST工程

原因 需要对带代码进行单元测试&#xff0c;选择在Visual studio 中使用GTEST 框架。 实施 创建一个常规的控制台可执行程序。然后使用NUGET安装包 安装GTEST 头文件和动态库&#xff0c;同时安装GTEST ADAPTER。 安装可能提示找不到包源&#xff0c;此时需要根据提示配置一…