【C++初阶】第十一站:list的介绍及使用

目录

list的介绍及使用

1.list的含义

2.list的介绍

3.list的使用

1.list的构造

2.list iterator的使用

3.list capacity

4.list element access

5 list modifiers

尾插尾删 和 头插头删

insert 和 erase

resize swap clear

6.list sort and reverse

7.list copy vector copy list

8.splice

9 list的迭代器失效


前言:

🎯个人博客:Dream_Chaser

🎈博客专栏:C++

📚本篇内容:list的介绍及使用

list的介绍及使用

1.list的含义

        列表是序列容器,允许在序列内的任何位置进行常量时间的插入和删除操作,以及两个方向的迭代。

容器的分类:

2.list的介绍

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

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

3. list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高效。

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

5. 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这可能是一个重要的因素)

3.list的使用

list中的接口比较多,此处类似,只需要掌握如何正确的使用,然后再去深入研究背后的原理,已达到可扩展的能力。以下为list中一些常见的重要接口

1.list的构造

构造函数( (constructor))
接口说明
list (size_type n, const value_type& val = value_type())
构造的 list 中包含 n 个值为 val 的元素
list()
构造空的 list
list (const list& x)
拷贝构造函数
list (InputIterator first, InputIterator last)
[first, last) 区间中的元素构造 list

void TestList1()
{
    list<int> l1;                         // 构造空的l1
    list<int> l2(4, 100);                 // l2中放4个值为100的元素
    list<int> l3(l2.begin(), l2.end());  // 用l2的[begin(), end())左闭右开的区间构造l3
    list<int> l4(l3);                    // 用l3拷贝构造l4

    // 以数组为迭代器区间构造l5
    int array[] = { 16,2,77,29 };
    list<int> l5(array, array + sizeof(array) / sizeof(int));

    // 列表格式初始化C++11
    list<int> l6{ 1,2,3,4,5 };

    // 用迭代器方式打印l5中的元素
    list<int>::iterator it = l5.begin();
    while (it != l5.end())
    {
        cout << *it << " ";
        ++it;
    }
    cout << endl;

    // C++11范围for的方式遍历
    for (auto& e : l5)
        cout << e << " ";

    cout << endl;
}

2.list iterator的使用

此处,大家可暂时将迭代器理解成一个指针,该指针指向list中的某个节点

函数声明
接口说明
begin +
end
返回第一个元素的迭代器 + 返回最后一个元素下一个位置的迭代器
rbegin +
rend
返回第一个元素的 reverse_iterator, end 位置 返回最后一个元素下一个位置的
reverse_iterator, begin 位置

【注意】

1. begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动

2. rbegin(end)与rend(begin)为反向迭代器,对迭代器执行++操作,迭代器向前移动

void TestList2()
{
    int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
    list<int> l(array, array + sizeof(array) / sizeof(array[0]));
    // 使用正向迭代器正向list中的元素
    // list<int>::iterator it = l.begin();   // C++98中语法
    auto it = l.begin();                     // C++11之后推荐写法
    while (it != l.end())
    {
        cout << *it << " ";
        ++it;
    }
    cout << endl;

    // 使用反向迭代器逆向打印list中的元素
    // list<int>::reverse_iterator rit = l.rbegin();
    auto rit = l.rbegin();
    while (rit != l.rend())
    {
        cout << *rit << " ";
        ++rit;
    }
    cout << endl;
}

3.list capacity

#include <iostream>
#include <list>

int main() {
    // 创建一个std::list并添加几个元素
    std::list<int> numbers = { 1, 2, 3, 4, 5 };

    // 使用size()方法打印列表中的元素数量
    std::cout << "The list contains " << numbers.size() << " elements." << std::endl;

    // 使用empty()方法检查列表是否为空,并打印结果
    if (numbers.empty()) {
        std::cout << "The list is empty." << std::endl;
    }
    else {
        std::cout << "The list is not empty." << std::endl;
    }

    // 移除所有元素后,再次使用empty()检查
    numbers.clear();
    if (numbers.empty()) {
        std::cout << "After clearing, the list is now empty." << std::endl;
    }

    return 0;
}

4.list element access

函数声明
接口说明
front
返回 list 的第一个节点中值的引用
back
返回 list 的最后一个节点中值的引用

5 list modifiers

函数声明
接口说明
push_front
list 首元素前插入值为 val 的元素
pop_front
删除 list 中第一个元素
push_back
list 尾部插入值为 val 的元素
pop_back
删除 list 中最后一个元素
insert
list position 位置中插入值为 val 的元素
erase
删除 list position 位置的元素
swap
交换两个 list 中的元素
clear
清空 list 中的有效元素
尾插尾删 和 头插头删

/ list迭代器的使用
// 注意:遍历链表只能用迭代器和范围for
void PrintList(const list<int>& l)
{
    // 注意这里调用的是list的 begin() const,返回list的const_iterator对象
    for (list<int>::const_iterator it = l.begin(); it != l.end(); ++it)
    {
        cout << *it << " ";
        // *it = 10; 编译不通过
    }

    cout << endl;
}

//list插入和删除
// push_back/pop_back/push_front/pop_front
void TestList3()
{
    int array[] = { 1, 2, 3 };
    list<int> L(array, array + sizeof(array) / sizeof(array[0]));

    // 在list的尾部插入4,头部插入0
    L.push_back(4);
    L.push_front(0);
    PrintList(L);

    // 删除list尾部节点和头部节点
    L.pop_back();
    L.pop_front();
    PrintList(L);
}

insert 和 erase

// insert /erase 
void TestList4()
{
    int array1[] = { 1, 2, 3 };
    list<int> L(array1, array1 + sizeof(array1) / sizeof(array1[0]));

    // 获取链表中第二个节点
    auto pos = ++L.begin();
    cout << *pos << endl;

    // 在pos前插入值为4的元素
    L.insert(pos, 4);
    PrintList(L);

    // 在pos前插入5个值为5的元素
    L.insert(pos, 5, 5);
    PrintList(L);

    // 在pos前插入[v.begin(), v.end)区间中的元素
    vector<int> v{ 7, 8, 9 };
    L.insert(pos, v.begin(), v.end());
    PrintList(L);

    // 删除pos位置上的元素
    L.erase(pos);
    PrintList(L);

    // 删除list中[begin, end)区间中的元素,即删除list中的所有元素
    L.erase(L.begin(), L.end());
    PrintList(L);
}

resize swap clear

void TestList5()
{
    // 用数组来构造list
    int array1[] = { 1, 2, 3 };
    list<int> l1(array1, array1 + sizeof(array1) / sizeof(array1[0]));
    PrintList(l1);

    // 交换l1和l2中的元素
    list<int> l2;
    l1.swap(l2);
    PrintList(l1);
    PrintList(l2);

    // 将l2中的元素清空
    l2.clear();
    cout << l2.size() << endl;
}

6.list sort and reverse

void test_list2()
{
	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;

	//sort(lt.begin(), lt.end());//为什么这个不能用呢?那是因为,list是双向迭代器
	//而标准库里面的sort支持随机迭代器,要用list自己的sort函数 lt.sort

	//升序 < less
	lt.sort();
	//降序 > greater();
	//greater<int> gt;
	//lt.sort(gt);

	//匿名对象的排序,降序
	lt.sort(greater<int>());
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;
}

7.list copy vector copy list

     代码测这种性能要把它换成 Release,debug的优化没有全开的,导致递归和循环,次数比较多,差异是比较大的,但是Release的差距不大。

void test_op()
{ 
	// 初始化随机数生成器,使用当前时间作为种子
	srand(time(0));
	// 定义常量N,表示要生成的随机数个数
	const int N = 1000000;

	//创建两个空的list容器
	list<int> lt1;
	list<int> lt2;
	// 循环N次,生成随机数并将其添加到两个list中
	for (int i = 0; i < N; i++)
	{
		auto e = rand(); // 生成一个随机数
		lt1.push_back(e); // 将随机数添加到lt1的末尾
		lt2.push_back(e); // 将相同的随机数添加到lt2的末尾
	}

	// 记录开始时间,单位为clock ticks(时钟滴答)
	int begin1 = clock();//返回程序所消耗的处理器时间。
	
	// 创建一个vector,使用lt2的begin和end迭代器初始化,复制lt2的内容
	vector<int> v(lt2.begin(), lt2.end());
	
	// 对vector v 进行排序,使用的是全局的std::sort函数,vector支持随机访问迭代器
	sort(v.begin(),v.end());

	// 将排序后的vector v的内容重新赋值给lt2,替换lt2当前的内容。
	lt2.assign(v.begin(),v.end());
	int end1 = clock(); // 记录结束时间

	int begin2 = clock(); // 记录另一个操作的开始时间
	lt1.sort(); // 直接对lt1进行排序,使用list容器自带的sort成员函数
	int end2 = clock(); // 记录结束时间

	// 输出两次排序操作所花费的时间(单位为clock ticks)
	printf("list copy vector sort copy list sort:%d\n",end1 - begin1);
	printf("list sort:%d\n",end2 - begin2);
}

8.unique and remove

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(3);
	lt.push_back(3);
	lt.push_back(3);
	lt.push_back(5);
	lt.push_back(5);
	lt.push_back(3);

	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;
	
	lt.sort();
	lt.unique();//去掉重复的
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;

	//lt.remove(30);//删除不存在的,不会报错
	lt.remove(3);
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;
}

8.splice

将元素从x转移到容器中,并将它们插入位置。

void test_list5()
{
	list<int> mylist1, mylist2;
	list<int>::iterator it;

	for (int i = 1; i <= 4; ++i)
	{
		mylist1.push_back(i);//mylist1: 1 2 3 4
	}

	for (int i = 1; i <= 3; i++)
	{
		mylist2.push_back(i*10);//mylist2:10 20 30
	}

	it = mylist1.begin();
	++it;   //指向mylist1里面的2元素
	
	for (auto e : mylist1)
	{
		cout << e << " ";
	}
	cout << endl;

	for (auto e : mylist2)
	{
		cout << e << " ";
	}
	cout << endl;
	
	//mylist1.splice(it,mylist2);//mylist1:1 10 20 30 2 3 4
							     //mylist2(empty)
	                            //"it" still points to 2 (the 5th element)
	
	//mylist1.splice(it, mylist2, ++mylist2.begin());//mylist:1 20 2 3 4
	//mylist1: 1 20 30 2 3 4

	mylist1.splice(it, mylist2, ++mylist2.begin(), mylist2.end());//mylist1:1 20 30 2 3 4 

	for (auto e : mylist1)
	{
		cout << e << " ";
	}
	cout << endl;

	for (auto e : mylist2)
	{
		cout << e << " ";
	}
	cout << endl;
}

list的迭代器失效

     前面说过,此处大家可将迭代器暂时理解成类似于指针,迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代器失效的只有在删除时才会失效并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响

pos这个位置使用完毕就失效了: 

改正:

void TestListIterator()
{
    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())
    {
        l.erase(it++); // it = l.erase(it);
    }
}

🔧本文修改次数:0

🧭更新时间:2024年 5 月 14 日 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

设计一个游戏的基本博弈框架

设计一个游戏的基本博弈框架&#xff0c;玩家通过操作改变某个数值&#xff0c;这个数值的变动会引发一系列实时变化&#xff0c;并且当这些数值累计到特定阈值时&#xff0c;会导致游戏中出现其他变化&#xff0c;可以分为以下几个步骤&#xff1a; 1. 确定游戏类型和主题 首…

GH263-045、GH263-035比例阀用电磁铁驱动放大器

GH263-045、GH263-035比例阀用电磁铁用于比例变量泵和油马达的控制&#xff0c;通过改变比例阀芯位置&#xff0c;可实现对比例变量泵的输出流量或油马达 转矩和转速的无级调节和远程控制&#xff0c;驱动电流分为GH263-035&#xff08;0.68A&#xff09;/GH263-045&#xff08…

未授权访问:Docker未授权访问漏洞

目录 1、漏洞原理 2、环境搭建 3、未授权访问 4、通过crontab反弹宿主机shell 防御手段 今天继续学习各种未授权访问的知识和相关的实操实验&#xff0c;一共有好多篇&#xff0c;内容主要是参考先知社区的一位大佬的关于未授权访问的好文章&#xff0c;还有其他大佬总结好…

五、Linux二进制安装MariaDB 六、MariaDB主从复制

目录 五、Linux二进制安装MariaDB1 卸载mariadb1.1 卸载相关的服务(mysql和mariadb都查询一下)1.2 查找MySQL和mariadb相关的文件目录 2 安装mariadb2.1 mariadb下载地址2.2 将安装包放入到服务器中并解压 (我放到opt下)2.3 将解压后的目录移动到安装目录下2.4 创建数据目录(根…

miniconda环境管理器安装及jupyter下载

1.miniconda简介 Miniconda是一款小巧的python环境管理工具&#xff0c;安装包大约只有50M多点&#xff0c;其安装程序中包含conda软件包管理器和Python。一旦安装了Miniconda&#xff0c;就可以使用conda命令安装任何其他软件工具包并创建环境等。 2.下载miniconda 查看需要的…

虚拟数字人及AI相关应用分享

一、虚拟数字人 1、简介 虚拟数字人可分为基础类和仿真智能类。可用于直播的&#xff0c;一般是仿真智能类&#xff1b;基础类动作缓慢&#xff0c;体验差&#xff0c;很容易被直播平台封号。 目前各大短视频平台上介绍的数字人&#xff0c;出于营销目的&#xff0c;有夸大宣传…

基于单片机的直流电机测速装置研究与设计

摘要: 基于单片机的直流电机测速装置采用了对直流电机的中枢供电回路串联取样电阻的方式实现对电机转速的精确实时测量。系统由滤波电路、信号放大电路、单片机控制电路以及稳压电源等功能模块电路构成。工作过程中高频磁环作为载体&#xff0c;利用电磁感应的基本原理对直流电…

Redis-持久化操作-RDB

Redis持久化 由于Redis的数据都存放在内存中&#xff0c;如果没有配置持久化&#xff0c;Redis重启后数据就全丢失了&#xff0c;于是需要开启 Redis的持久化功能&#xff0c;将数据保存到磁盘上&#xff0c;当Redis重启后&#xff0c;可以从磁盘中恢复数据。 Redis提供了两个…

利用一段代码轻松绕过PHP授权系统

第一步&#xff1a;首先你需要改名全局文件 比如说全局文件 common.php&#xff0c;那么 你将他改为core.php 第二步&#xff1a;创建文件 创建一个文件&#xff0c;和改名前的全局文件名称一样&#xff0c;然后把以下代码复制进去就OK了 代码如下&#xff1a; <?php…

免费分享一套SpringBoot+Vue教务管理(课程管理)系统,帅呆了~~

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的SpringBootVue教务管理(课程管理)系统&#xff0c;分享下哈。 项目视频演示 【免费】SpringBootVue教务管理(课程管理)系统 Java毕业设计_哔哩哔哩_bilibili【免费】SpringBootVue教务管理(课程管理)系统 …

html5的一些新特性

最近总是碰到html5特性这种问题,虽然简单,但是也是自己平时不关注的东西,趁今天时间充裕,那就来总结一下吧 HTML5新特性包括新增了部分标签、表单元素增强、支持视频和音频、支持canvas绘图、提供web存储、提供地理定位功能、提供web workers机制、提供web socket协议、提供CS…

Django 安全性与防御性编程:如何保护 Django Web 应用

title: Django 安全性与防御性编程&#xff1a;如何保护 Django Web 应用 date: 2024/5/13 20:26:58 updated: 2024/5/13 20:26:58 categories: 后端开发 tags: CSRFXSSSQLUploadHTTPOnlyPasswordSession 跨站请求伪造&#xff08;CSRF&#xff09; 跨站请求伪造&#xff0…

【HarmonyOS】笔记八-图片处理

概念 开发者经常需要在应用中显示一些图片&#xff0c;例如&#xff1a;按钮中的icon、网络图片、本地图片等。在应用中显示图片需要使用Image组件实现&#xff0c;Image支持多种图片格式&#xff0c;包括png、jpg、bmp、svg和gif&#xff0c;该接口通过图片数据源获取图片&am…

垃圾回收器

首先先来回答一下上篇文章中最后留给大家的问题&#xff1a; 为什么分代GC算法要把堆分为年轻代和老年代&#xff1f; 系统中的大部分对象&#xff0c;都是创建出来之后很快就不再使用可以被回收&#xff0c;比如用户获取订单数据&#xff0c;订单数据返回给用户之后就可以释放…

【软考高项】四十五、项目管理科学计算之工程经济学

一、资金的时间价值与等值计算的概念 1、资金的时间价值是指不同时间发生的等额资金在价值上的差别。 2、把资金存入银行,经过一段时间后也会产生增值,这就是利息。 例如,在年利率为5.22%条件下&#xff0c;当年的100元与下一年的105.22元是等值的,即100 &#xff08;15.22%&a…

银行业务基础:深入解析表内业务与表外业务的概念

1、表内业务 表内业务是指银行在资产负债表内反映的业务&#xff0c;这些业务直接影响银行的资产和负债总额。表内业务是银行经营的主要活动&#xff0c;通常包括以下几个方面&#xff1a; &#xff08;1&#xff09;资产业务&#xff1a;主要是指银行通过其资金运用&#xff…

机器学习案例:加州房产价格(三)

参考链接&#xff1a;https://hands1ml.apachecn.org/2/#_11 创建测试集 继续你的数据工作之旅。 现在你需要再仔细调查下数据以决定使用什么算法。 如果你查看了测试集&#xff0c;就会不经意地按照测试集中的规律来选择某个特定的机器学习模型。再当你使用测试集来评估误差…

SpringCloud------Eureka,Ribbon,Nacos

认识微服务 微服务技术栈 微服务概念 微服务结构 微服务技术对比 企业需求 SpringCloud 认识Springcloud 服务拆分及远程调用 每个服务只能查询自己数据库中的表&#xff0c;导致其他服务如果想使用别人的表数据&#xff0c;这就需要进行远程调用&#xff0c;这里使用RestTem…

Ubuntu 20.04在Anaconda虚拟环境中配置PyQt4

一、创建一个虚拟环境 1 创建一个python2.7的虚拟环境&#xff1a; conda create -n pyqt4 numpy matplotlib python2.72 在环境中安装几个需要的包&#xff1a; pip install Theano pip install python-opencv3.4.0.14 pip install qdarkstyle pip install dominate二、在主…

【java-数据结构14-双向链表的增删查改2】

上一篇文章中&#xff0c;我们已经对双向链表进行一些基本操作&#xff0c;本篇文章我们继续通过对链表的增删查改来加深对链表的理解~同时有任何不懂的地方可以在评论区留言讨论&#xff0c;也可以私信小编~觉得小编写的还可以的可以留个关注支持一下~话不多说正片开始~ 注意…