C++——list的了解和使用

目录

引言

forward_list与list

标准库中的list

一、list的常用接口

1.list的迭代器

2.list的初始化

3.list的容量操作

4.list的访问操作

5.list的修改操作

6.list的其他操作

二、list与vector的对比

结束语


引言

本篇博客要介绍的是STL中的list。

求点赞收藏评论关注!!!十分感谢!!!

forward_list与list

首先我们先简单了解一下forward_list与list:

forward_list与list都是C++标准模板库(STL)中的容器,它们提供了不同的链表实现,适用于不同的场景。

forward_list

定义与结构:

1.forward_list是C++11引入的一种容器,它提供了一种单向链表的数据结构。

2.它只维护一个指向下一个节点的指针,因此内存使用相对高效。

特点:

1.只能在单向遍历,即只能从前往后遍历,不能反向遍历。

2.在已知位置的情况下,插入和删除操作非常高效,时间复杂度为O(1)。

3.不支持通过索引访问元素,只能使用迭代器进行访问。

适用场景:

1.适用于需要频繁进行前向遍历和插入、删除操作的场景。

2.当内存使用要求较高,且不需要双向遍历时,forward_list是更好的选择。

list

定义与结构:

1.list是C++标准库中基于带头双向循环链表实现的容器。

2.它支持双向迭代器,可以从前往后和从后往前遍历。

特点:

1.在任何位置进行插入和删除操作的时间复杂度都是近似O(1)。

2.支持双向遍历,迭代器使用更灵活。

3.与forward_list相比,内存占用稍多,因为每个节点需要维护两个指针(一个指向前一个节点,一个指向下一个节点)。

适用场景:

1.适用于需要双向遍历和更灵活操作的场景。

2.当需要在列表中间频繁插入或删除元素时,list是更好的选择。

具体内容可以看看这两篇文章:

数据结构——单链表

数据结构——双向链表

本文的重点是list。

标准库中的list

一、list的常用接口

list接口

1.list的迭代器

list的迭代器访问元素与我们之前学习的其他容器的迭代器访问一样。

int main()
{
	list<int> li = { 1, 2, 3, 4, 5 };
	list<int>::iterator it = li.begin();
	cout << "顺序遍历:";
	while (it != li.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
	cout << "逆序遍历:";
	list<int>::reverse_iterator rit = li.rbegin();
	while (rit != li.rend())
	{
		cout << *rit << " ";
		++rit;
	}
	return 0;
}

由于list的迭代器是双向迭代器,支持++和--操作,因此可以在list中向前和向后遍历。

2.list的初始化

list的初始化与我们之前学习的其他容器的初始化一样,我们直接看个简单的使用示例:

int main()
{
    // 默认构造函数
    list<int> numbers1;
    cout << "默认构造: ";
    for (const auto& num : numbers1) 
    {
        cout << num << " ";
    }
    cout << endl;
    // n个val构造
    list<int> numbers2(5, 5);
    cout << "n个val构造: ";
    for (const auto& num : numbers2) 
    {
        cout << num << " ";
    }
    cout << endl;

    int arr[] = { 1, 2, 3, 4, 5 };
    // 通过vector的迭代器初始化
    list<int> numbers3(arr, arr + sizeof(arr) / sizeof(arr[0]));
    cout << "迭代器区间构造: ";
    for (const auto& num : numbers3) 
    {
        cout << num << " ";
    }
    cout << endl;

    list<int> numbers4 = { 6, 7, 8, 9, 10 };
    // 拷贝构造
    list<int> numbers5(numbers4);
    cout << "拷贝构造: ";
    for (const auto& num : numbers5) 
    {
        cout << num << " ";
    }
    cout << endl;

    numbers1 = numbers2;
    // 赋值重载
    cout << "赋值重载: ";
    for (const auto& num : numbers1) 
    {
        cout << num << " ";
    }
    cout << endl;
    return 0;
}

输出结果为:

3.list的容量操作
函数名称功能
size返回列表中元素的数量
max_size返回列表可容纳的最大元素数量
empty检查列表是否为空,是则返回 true,否则返回 false
resize重新设置列表中元素的数量,超过原来数量则用默认值填充
clear清空列表中的所有元素

这些函数也是很容易理解的,我们还是直接看代码示例:

int main()
{
	list<int> li = { 1,2,3,4,5 };
	cout << "Size of list: " << li.size() << endl;
	cout << "Max size of list: " << li.max_size() << endl;
	if (li.empty())
	{
		cout << "empty" << endl;
	}
	else
	{
		cout << "not empty" << endl;
	}
	li.clear();
	if (li.empty())
	{
		cout << "empty" << endl;
	}
	else
	{
		cout << "not empty" << endl;
	}
	return 0;
}

输出结果为

与deque这一容器一样,list也没有reserve这一接口。

int main()
{
	list<int> li = { 1,2,3 };
	li.resize(5);
	for (auto& num : li)
	{
		cout << num << " ";
	}
	cout << endl;
	li.resize(2);
	for (auto& num : li)
	{
		cout << num << " ";
	}
	return 0;
}

输出结果为;

4.list的访问操作
函数名称功能
back返回列表最后一个元素
front返回列表第一个元素

由于list 是一个双向链表,不支持高效的随机访问。在链表中,访问某个元素需要从头节点开始顺序遍历,直到找到目标元素。因此,为 list 提供下标运算符或 at 方法并不合适。

访问操作的使用示例如下:

int main()
{
	list<int> li = { 1,2,3 };
	cout << li.front() << endl;
	cout << li.back() << endl;

	return 0;
}

输出结果为:

5.list的修改操作

常用的修改操作有如下几个:

函数名称功能
push_back在列表尾部添加元素
push_front在列表头部添加元素
pop_back删除列表最后一个元素
pop_front删除列表第一个元素
insert在指定位置插入元素
erase删除指定位置或区间的元素
swap交换两个列表
assign使用指定列表替换原列表

这些接口我们也是十分熟悉了,我们直接看代码示例:

尾删和尾插:

int main()
{
	list<int> li;
	li.push_back(1);
	li.push_back(2);
	li.push_back(3);
	li.push_back(4);
	for (auto& num : li) 
	{
		cout << num << " ";
	}
	cout << endl;
	li.pop_back();
	for (auto& num : li)
	{
		cout << num << " ";
	}
	cout << endl;
	return 0;
}

输出结果为:

头删和头插:

int main()
{
	list<int> li;
	li.push_front(1);
	li.push_front(2);
	li.push_front(3);
	li.push_front(4);
	for (auto& num : li)
	{
		cout << num << " ";
	}
	cout << endl;
	li.pop_front();
	for (auto& num : li)
	{
		cout << num << " ";
	}
	cout << endl;
	return 0;
}

输出结果为:

assign和swap:

int main()
{
	list<int> li1 = { 1,1,1,1,1 };
	li1.assign(3, 3);
	for (auto& num : li1)
	{
		cout << num << " ";
	}
	cout << endl;
	list<int> li2 = { 2,2,2,2,2 };
	li1.swap(li2);
	for (auto& num : li1)
	{
		cout << num << " ";
	}
	cout << endl;
	for (auto& num : li2)
	{
		cout << num << " ";
	}
	return 0;
}

输出结果为:

insert:

int main()
{
	list<int> li = { 1,2,3,4,5 };
	list<int>::iterator it = li.begin();
	it = li.insert(it, 6);
	it = li.insert(it, 7);
	for (auto& num : li)
	{
		cout << num << " ";
	}
	return 0;
}

输出结果为:

erase:

int main()
{
	list<int> li = { 1,2,3,4,5 };
	list<int>::iterator it = li.begin();
	it = li.erase(it);
	for (auto& num : li)
	{
		cout << num << " ";
	}
	return 0;
}

输出结果为:

6.list的其他操作

接下来我们来学习list的其他操作:

函数名称功能描述
splice将元素从一个列表转移到另一个列表
remove移除具有特定值的元素
remove_if移除满足条件的元素
unique移除重复的值
sort对容器中的元素进行排序
merge合并已排序的列表
reverse反转元素的顺序

splice:

splice 是 list 提供的一个成员函数,用于将一个列表(list)中的元素移动到另一个列表中,而不需要进行元素复制或移动操作。

使用示例:

int main()
{
	list<int> li1 = { 1,2,3 };
	list<int> li2 = { 4,5,6 };
	list<int> li3 = { 7,8,9 };
	list<int> li4 = { 0 };
	// 将 li2 的所有元素拼接到 li1 的末尾
	// li1 现在包含 {1, 2, 3, 4, 5, 6}
	// li2 现在为空 {}
	li1.splice(li1.end(), li2);
	for (auto num : li1)
	{
		cout << num << " ";
	}
	cout << endl;
	// 获取 li3 的迭代器,指向第一个元素(7)
	auto begin1 = li3.begin();
	// 将迭代器向前移动一位,指向第二个元素(8)
	++begin1;

	// 将 li3 的第一个元素(7)移动到 li4 的末尾
	// li4 现在包含 {0, 7}
	// li3 现在包含 {8, 9}
	li4.splice(li4.end(), li3, li3.begin(), begin1);
	for (auto num : li4)
	{
		cout << num << " ";
	}
	return 0;
}

输出结果为:

remove:

用于从容器中移除所有等于指定值的元素。

与成员函数 erase 不同,成员函数 erase 按元素的位置擦除元素(使用迭代器),此函数  按元素的值删除元素。

int main()
{
	list<int> li = { 1,2,3,3,4,5 };
	li.remove(3);
	for (auto num : li)
	{
		cout << num << " ";
	}
	cout << endl;

	return 0;
}

输出结果为:

remove_if:

用于从容器中移除满足特定条件的元素。

bool fun(int num)
{
	return num == 3;
}

int main()
{
	list<int> li = { 1,2,3,3,4,5 };
	li.remove_if(fun);
	for (auto num : li)
	{
		cout << num << " ";
	}
	cout << endl;

	return 0;
}

输出结果为:

unique:

用于移除容器中连续重复的元素。

int main()
{
	list<int> li = { 1,2,3,3,4,5 };
	li.unique();
	for (auto num : li)
	{
		cout << num << " ";
	}
	return 0;
}

输出结果为:

sort:

用于对容器中的元素进行排序。

int main()
{
	list<int> li = { 9,1,5,3,2,4,8,0,7,6 };
	li.sort();
	for (auto num : li)
	{
		cout << num << " ";
	}
	return 0;
}

输出结果为:

merge:

用于将两个已排序的范围合并成一个有序范围。

要求输入的两个范围必须是有序的(通常是升序)。它会将两个范围中的元素按顺序合并到目标范围中。目标范围必须有足够的空间来存储合并后的结果。

int main()
{
	list<int> li1 = { 1,3,2,5,7 };
	list<int> li2 = { 2,3,4,6,8 };
	li1.sort();
	li2.sort();
	li1.merge(li2);
	for (auto num : li1)
	{
		cout << num << " ";
	}
	return 0;
}

输出结果为:

reverse:

用于反转容器中元素的顺序。

int main()
{
	list<int> li = { 9,1,5,3,2,4,8,0,7,6 };
	li.reverse();
	for (auto num : li)
	{
		cout << num << " ";
	}
	return 0;
}

输出结果为:

二、list与vector的对比

vectorlist
底层结构动态顺序表,一段连续空间带头结点的双向循环链表
随机访问支持随机访问,访问某个元素效率O(1)不支持随机访问,访问某个元素效率O(N)
插入和删除任意位置插入和删除效率低,需要搬移元素,时间复杂度为O(N),插入时有可能需要增容,增容:开辟新空间,拷贝元素,释放旧空间,导致效率更低任意位置插入和删除效率高,不需要搬移元素,时间复杂度为0(1)
空间利用率底层为连续空间,不容易造成内存碎片,空间利用率高,缓存利用率高底层节点动态开辟,小节点容易造成内存碎片,空间利用率低,缓存利用率低
迭代器原生态指针对原生态指针(节点指针)进行封装
迭代器失效在插入元素时,要给所有的迭代器重新赋值,因为插入元素有可能会导致重新扩容,致使原来迭代器失效,删除时,当前迭代器需要重新赋值否则会失效插入元素不会导致选代器失效,删除元素时,只会导致当前迭代器失效,其他迭代器不受影响
使用场景需要高效存储,支持随机访问,不关心插入删除效率大量插入和删除操作,不关心随机访问

结束语

求点赞收藏评论关注!!!

感谢各位大佬的支持!!!

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

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

相关文章

Elasticsearch+kibana安装(简单易上手)

下载ES( Download Elasticsearch | Elastic ) 将ES安装包解压缩 解压后目录如下: 修改ES服务端口&#xff08;可以不修改&#xff09; 启动ES 记住这些内容 验证ES是否启动成功 下载kibana( Download Kibana Free | Get Started Now | Elastic ) 解压后的kibana目…

Ansible自动化运维实战--script、unarchive和shell模块(6/8)

文章目录 一、script模块1.1、功能1.2、常用参数1.3、举例 二、unarchive模块2.1、功能2.2、常用参数2.3、举例 三、shell模块3.1、功能3.2、常用参数3.3、举例 一、script模块 1.1、功能 Ansible 的 script 模块允许你在远程主机上运行本地的脚本文件&#xff0c;其提供了一…

Unity Epplus读取excel表并存入So文件举例

目录 此篇需要你有一定的阅读代码的能力&#xff0c;不然点开了也不知道在做什么 这是读表工具 So文件这么写 使用 此篇需要你有一定的阅读代码的能力&#xff0c;不然点开了也不知道在做什么 在此之前你需要知道epplus是干什么的&#xff0c;然后知道其基本api&#xff0…

Java Web-Cookie与Session

会话跟踪技术 会话跟踪技术是一种在 Web 应用程序中跟踪用户会话状态的机制&#xff0c;它允许服务器在多个请求之间识别和关联属于同一用户的请求&#xff0c;以便在整个会话过程中保持用户相关的信息。以下是几种常见的会话跟踪技术&#xff1a; Cookie 概念&#xff1a;Cook…

Spring Boot(6)解决ruoyi框架连续快速发送post请求时,弹出“数据正在处理,请勿重复提交”提醒的问题

一、整个前言 在基于 Ruoyi 框架进行系统开发的过程中&#xff0c;我们常常会遇到各种有趣且具有挑战性的问题。今天&#xff0c;我们就来深入探讨一个在实际开发中较为常见的问题&#xff1a;当连续快速发送 Post 请求时&#xff0c;前端会弹出 “数据正在处理&#xff0c;请…

YOLOv8改进,YOLOv8检测头融合DynamicHead,并添加小目标检测层(四头检测),适合目标检测、分割等,全网独发

摘要 作者提出一种新的检测头,称为“动态头”,旨在将尺度感知、空间感知和任务感知统一在一起。如果我们将骨干网络的输出(即检测头的输入)视为一个三维张量,其维度为级别 空间 通道,这样的统一检测头可以看作是一个注意力学习问题,直观的解决方案是对该张量进行全自…

C语言编译过程全面解析

今天是2025年1月26日&#xff0c;农历腊月二十七&#xff0c;一个距离新春佳节仅一步之遥的日子。城市的喧嚣中&#xff0c;年味已悄然弥漫——能在这个时候坚持上班的人&#xff0c;真可称为“牛人”了吧&#xff0c;哈哈。。。。 此刻&#xff0c;我在重新审视那些曾被遗忘的…

在php中怎么打开OpenSSL

&#xff08;点击即可进入聊天助手&#xff09; 背景 在使用php做一些项目时,有用到用户邮箱注册等,需要开启openssl的能力 在php系统中openssl默认是关闭状态的,在一些低版本php系统中,有的甚至需要在服务器终端后台,手动安装 要打开OpenSSL扩展&#xff0c;需要进行以下步骤 …

【数据分享】2014-2025年我国水系数据(免费获取/全国/分省)

水系数据是我们在各项研究中经常使用的数据&#xff01;水系数据虽然很常用&#xff0c;但是却基本没有能下载最近年份水系数据的网站&#xff0c;所以很多人不知道如何获得水系数据。 本次我们给大家分享的是2014-2025年的全国范围的水系数据&#xff0c;包括水系线数据和水系…

Office2021下载与安装保姆级教程【Office Tool Plus】

Office Tool Plus安装Office2021 下载Office Tool Plus安装OfficeⅠ. 清除旧版本Ⅱ. 配置安装参数Ⅲ. 安装许可证Ⅳ. 激发&#xff08;JH&#xff09;Office 本文介绍使用Office Tool Plus工具下载、安装、部署Office 2021全过程。 下载Office Tool Plus OfficeToolPlus是一个…

DeepSeek明确学术研究方向效果如何?

明确学术研究方向 在学术写作中&#xff0c;选择一个出色的研究主题至关重要&#xff0c;因为它直接关系到论文是否能登上高级别的学术期刊。不少学者在这个过程中走入了误区&#xff0c;他们往往将大把的时间花在写作本身&#xff0c;而忽略了对选题的深入思考&#xff0c;这…

Spring MVC 综合案例

目录 一. 加法计算器 1. 准备工作 2. 约定前后端交互接口 需求分析 接口定义 3. 服务器端代码 4. 运行测试 二. 用户登录 1. 准备工作 2. 约定前后端交互接口 需求分析 接口定义 (1) 登录界面接口 (2) 首页接口 3. 服务器端代码 4. 运行测试 三. 留言板 1. 准备…

基于OSAL的嵌入式裸机事件驱动框架——消息队列osal_msg

参考B站up主【架构分析】嵌入式祼机事件驱动框架 感谢大佬分享 消息队列 消息分为hdr和bdy&#xff0c;把消息的头dhr和内容bdy做了一个分离的设计 dhr包括指向下一个消息的指针next&#xff0c;len在创建消息的时候使用&#xff0c;dest_id即目标任务&#xff0c;将消息和任务…

Github 2025-01-25Rust开源项目日报Top10

根据Github Trendings的统计,今日(2025-01-25统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Rust项目10Python项目1Vue项目1JavaScript项目1Deno: 现代JavaScript和TypeScript运行时 创建周期:2118 天开发语言:Rust, JavaScript协议类型…

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】1.8 随机数奥秘:生成符合现实分布的虚拟数据

1.8 随机数奥秘&#xff1a;生成符合现实分布的虚拟数据 目录 #mermaid-svg-wHqPAE3mMd8HNYmi {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-wHqPAE3mMd8HNYmi .error-icon{fill:#552222;}#mermaid-svg-wHqPAE3mM…

使用vitepress搭建自己的博客项目

一、介绍can-vitepress-blog 什么是CAN BLOG CAN BLOG是基于vitepress二开的个人博客系统&#xff0c;他能够方便使用者快速构建自己的博客文章&#xff0c;无需繁琐的配置和复杂的代码编写。 CAN BLOG以antdv为UI设计基础&#xff0c;简洁大方&#xff0c;界面友好&#xf…

STranslate 中文绿色版即时翻译/ OCR 工具 v1.3.1.120

STranslate 是一款功能强大且用户友好的翻译工具&#xff0c;它支持多种语言的即时翻译&#xff0c;提供丰富的翻译功能和便捷的使用体验。STranslate 特别适合需要频繁进行多语言交流的个人用户、商务人士和翻译工作者。 软件功能 1. 即时翻译&#xff1a; 文本翻译&#xff…

【数据结构】_链表经典算法OJ:合并两个有序数组

目录 1. 题目描述及链接 2. 解题思路 3. 程序 3.1 第一版 3.2 第二版 1. 题目描述及链接 题目链接&#xff1a;21. 合并两个有序链表 - 力扣&#xff08;LeetCode&#xff09; 题目描述&#xff1a; 将两个升序链表合并为一个新的 升序 链表并返回。 新链表是通过拼接给…

51单片机开发:动态数码管

实验目标&#xff1a;使8个数码管依次显示01234567。 动态数码管的原理图如下图所示&#xff1a;两个四位一体的数码管&#xff0c;其段选接在P0端口上。下表以数字0为例&#xff0c;描述端口输出值与数码管显示的对照关系。 dpgfedcbaP07P06P05P04P03P02P01P00001111110x3f&…

84,【8】BUUCTF WEB [羊城杯 2020]Blackcat

进入靶场 音乐硬控我3分钟 回去看源码 <?php // 检查 POST 请求中是否包含 Black-Cat-Sheriff 和 One-ear 字段 // 如果任意一个字段为空&#xff0c;则输出错误信息并终止脚本执行 if(empty($_POST[Black-Cat-Sheriff]) || empty($_POST[One-ear])){die(请提供 Black-C…