【STL】list 双向循环链表的使用介绍

news2025/1/22 14:47:01

STL中list容器的详细使用说明

  • 一.list的文档介绍
  • 二. list的构造函数
  • 三.list中的访问与遍历操作
  • 四.list中的修改操作
    • 4.1 list中的各种修改操作
    • 4.2 list的迭代器失效问题
  • 五.list中的其他一些操作

一.list的文档介绍

  1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代
  2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。
  3. listforward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高效。
  4. 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好。
  5. 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这可能是一个重要的因素)

二. list的构造函数

下面列举几个最常用构造函数:

construct(构造函数)接口说明
list()默认构造,构造一个空链表
list (const list& x)拷贝构造函数
list (size_type n, const value_type& val = value_type())用n个val构造list
list (InputIterator first, InputIterator last)用一段迭代器区间 [first,last)构造list
list (initializer_list<value_type> il)C++11新支持的,用一个初始化列表构造list

举例演示一下如何使用:

int main()
{
	//默认构造
	list<int> l1;
	//n个val构造
	list<int> l2(10, 1);
	//拷贝构造
	list<int> l3 = l2;  // or list<int> l3(l2);
	//初始化列表
	list<int> l4 = { 1,2,3,4,5 }; // or list<int> l4{1,2,3,4,5};
	return 0;
}

想了解更多list构造函数的朋友可以去文档查看一下 list

三.list中的访问与遍历操作

== 因为list容器并没有重载[]运算符,因为效率不高,所以我们只能通过迭代器的方式来访问list中的数据==
接口说明如下:

函数声明接口说明
begin()返回list第一个元素位置的迭代器
end()返回list容器最后一个元素的下一个位置的迭代器
rbegin()返回list最后一个元素位置的反向迭代器
rend()返回list第一个元素的前一个位置的反向迭代器
front()返回list中第一个元素的引用
back()返回list中最后一个元素的引用

这里说明一下,因为list是双向循环链表所以list的迭代器是双向迭代器,可以++或者–,但是不是随机迭代器,因为不支持+=和-=,因此algorithm库中的sort函数的参数不能是list的迭代器,这里特别注意一下!

举例:

int main()
{
	list<int> lt = { 1,2,3,4,5,6 };

	list<int>::iterator it = lt.begin();
	while (it != lt.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
	
	list<int>::reverse_iterator rit = lt.rbegin();
	while (rit != lt.rend())
	{
		cout << *rit << " ";
		++rit;
	}
	cout << endl;
	return 0;
}

输出结果如下:

1 2 3 4 5 6
6 5 4 3 2 1

当然,有迭代器就也可以使用范围for遍历!

四.list中的修改操作

4.1 list中的各种修改操作

函数声明接口说明
push_front(const value_type& val)在list的首元素前插入值为val的节点
pop_front()删除list中的首个节点
push_back (const value_type& val)在list最后一个元素后插入值为val的节点
pop_back()删除list中最后一个节点
iterator insert (const_iterator position, const value_type& val)在list position 位置中插入值为val的元素
erase(const_iterator position)删除list position位置的元素
assign (size_type n, const value_type& val)将新内容分配给list容器,替换其当前内容,并相应地修改其大小
swap(list& x)交换两个list中的元素
clear()清空list

举例:

int main()
{
	list<int> lt1 = { 1,2,3,4,5,6,7,8,9 };

	for (const auto& e : lt1)
	{
		cout << e << " ";
	}
	cout << endl;

	lt1.push_front(0);
	lt1.push_back(10);
	for (const auto& e : lt1)
	{
		cout << e << " ";
	}
	cout << endl;

	lt1.insert(++lt1.begin(), 100);
	lt1.erase(--lt1.end());
	for (const auto& e : lt1)
	{
		cout << e << " ";
	}
	cout << endl;

	lt1.assign(10, 0);
	for (const auto& e : lt1)
	{
		cout << e << " ";
	}
	cout << endl;

	lt1.clear();

	return 0;
}

输出结果:

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

4.2 list的迭代器失效问题

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

错误示范:

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

正确写法:

// 改正
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);
 }
}

五.list中的其他一些操作

函数声明接口说明
splice (const_iterator position, list& x)将x链表剪切到position位置
remove(const value_type& val)从容器中删除所有比较等于 val 的元素
unique()删除list中的重复元素(注意:要先对list中的元素排序)
merge (list& x)通过将 x 各自排序位置的所有元素传输到容器中,将 x 合并到列表中(两个容器都已排序
sort (Compare comp)将list中的元素按Compare方式进行排序
reverse()逆置链表

举例:

int main()
{
	list<int> lt1 = { 1,2,3,4,5,6,7,8,9 };
	list<int> lt2 = { 10,20,30,40,50,60 };
	lt1.splice(find(lt1.begin(), lt1.end(), 5), lt2);
	cout << "lt1:";
	for (const auto& e : lt1)
	{
		cout << e << " ";
	}
	cout << endl;
	cout << "lt2:";
	for (const auto& e : lt2)
	{
		cout << e << " ";
	}
	cout << endl;
	cout << "remove 9:";
	lt1.remove(9);
	for (const auto& e : lt1)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}

输出结果:

lt1:1 2 3 4 10 20 30 40 50 60 5 6 7 8 9
lt2:
remove 9:1 2 3 4 10 20 30 40 50 60 5 6 7 8


至此,list中的基本操作就全部介绍完了, 观众老爷们点赞一下吧!

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

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

相关文章

html学习笔记(3)

一、文本格式标签 效果标签&#xff08;旧版&#xff09;标签&#xff08;语义化&#xff0c;强调&#xff09;加粗<b><strong>倾斜<i><em>下划线<u><ins>删除线<s><del> 前面的标签 b 、 i 、 u 、 s 就仅仅是实现加粗、倾…

Postgresql源码(141)JIT系列分析汇总

JIT的东西比较零散&#xff0c;本篇对之前的一些列分析做个汇总、整理。 涉及&#xff1a; 《Postgresql源码&#xff08;113&#xff09;表达式JIT计算简单分析》 《Postgresql源码&#xff08;127&#xff09;投影ExecProject的表达式执行分析》 《Postgresql源码&#xff08…

Maven多环境打包方法配置

简单记录一下SpringBoot多环境打包配置方法&#xff0c;分部署环境和是否包含lib依赖包两个维度 目录 一、需求说明二、目录结构三、配置方案四、验证示例 一、需求说明 基于Spring Boot框架的项目分开发&#xff0c;测试&#xff0c;生产等编译部署环境&#xff08;每一个环境…

SDL2基本使用

前言 在这里记录SDL的环境基本搭建和使用&#xff0c;方便回忆。使用该图形库也是为了方便在没有单片机和显示模块的使用&#xff0c;也能对简单验证些关于图形构建或界面管理的猜想和测试&#xff0c;所以下述不会探讨过于深入的东西。当然&#xff0c;也可以通过SDL官网查看介…

【Linux系统编程】—— 从零开始实现一个简单的自定义Shell

文章目录 什么是自主shell命令行解释器&#xff1f;实现shell的基础认识全局变量的配置初始化环境变量实现内置命令&#xff08;如 cd 和 echo&#xff09;cd命令&#xff1a;echo命令&#xff1a; 构建命令行提示符获取并解析用户输入的命令执行内置命令与外部命令Shell的主循…

认识BOM

BOM 弹出层 可视窗口尺寸 屏幕宽高 浏览器内核和其操作系统的版本 剪贴板 是否允许使用cookie 语言 是否在线

[c语言日寄]结构体的使用及其拓展

【作者主页】siy2333 【专栏介绍】⌈c语言日寄⌋&#xff1a;这是一个专注于C语言刷题的专栏&#xff0c;精选题目&#xff0c;搭配详细题解、拓展算法。从基础语法到复杂算法&#xff0c;题目涉及的知识点全面覆盖&#xff0c;助力你系统提升。无论你是初学者&#xff0c;还是…

Linux系统的第一个进程是什么?

Linux进程的生命周期从创建开始&#xff0c;直至终止&#xff0c;贯穿了一个进程的整个存在过程。我们可以通过系统调用fork()或vfork()来创建一个新的子进程&#xff0c;这标志着一个新进程的诞生。 实际上&#xff0c;Linux系统中的所有进程都是由其父进程创建的。 既然所有…

5. 马科维茨资产组合模型+AI金融智能体(qwen-max)识别政策意图方案(理论+Python实战)

目录 0. 承前1. AI金融智能体1.1 What is AI金融智能体1.2 Why is AI金融智能体1.3 How to AI金融智能体 2. 数据要素&计算流程2.1 参数集设置2.2 数据获取&预处理2.3 收益率计算2.4 因子构建与预期收益率计算2.5 协方差矩阵计算2.6 投资组合优化2.7 持仓筛选2.8 AI金融…

PostMan最新版本及离线安装指南

本文还有配套的精品资源&#xff0c;点击获取 简介&#xff1a;PostMan是一款流行的API测试工具&#xff0c;它提供了一个直观的用户界面&#xff0c;方便Web开发者和测试人员进行接口测试。本文将指导你如何安装最新版的PostMan&#xff0c;包括在线安装和离线安装两种方法。…

记录一次k8s起不来的排查过程

我在k8s集群&#xff0c;重启了一个node宿主机&#xff0c;竟然发现kubelet起不来了&#xff01;报错如下 这个报错很模糊&#xff0c;怎么排查呢。这样&#xff0c;开两个界面&#xff0c;一个重启kubelet&#xff0c;一个看系统日志(/var/log/message:centos&#xff0c;/va…

grafana + Prometheus + node_exporter搭建监控大屏

本文介绍生产系统监控大屏的搭建&#xff0c;比较实用也是实际应用比较多的方式&#xff0c;希望能够帮助大家对监控系统有一定的认识。 0、规划 grafana主要是展示和报警&#xff0c;Prometheus用于保存监控数据&#xff0c;node_exporter用于实时采集各个应用服务器的事实状…

2024年博客之星主题创作|从零到一:我的技术成长与创作之路

2024年博客之星主题创作&#xff5c;从零到一&#xff1a;我的技术成长与创作之路 个人简介个人主页个人成就热门专栏 历程回顾初来CSDN&#xff1a;怀揣憧憬&#xff0c;开启创作之旅成长之路&#xff1a;从平凡到榜一的蜕变持续分享&#xff1a;打卡基地与成长复盘四年历程&a…

Golang的网络编程安全

Golang的网络编程安全 一、Golang网络编程的基本概念 作为一种现代化的编程语言&#xff0c;具有优秀的并发特性和网络编程能力。在Golang中&#xff0c;网络编程是非常常见的需求&#xff0c;可以用于开发各种类型的网络应用&#xff0c;比如Web服务、API服务、消息队列等。Go…

【2024年华为OD机试】(C/D卷,200分)- 5G网络建设 (JavaScriptJava PythonC/C++)

一、问题描述 题目描述 现需要在某城市进行5G网络建设&#xff0c;已经选取N个地点设置5G基站&#xff0c;编号固定为1到N。接下来需要各个基站之间使用光纤进行连接以确保基站能互联互通。不同基站之间假设光纤的成本各不相同&#xff0c;且有些节点之间已经存在光纤相连。 …

消息队列篇--原理篇--RabbitMQ和Kafka对比分析

RabbitMQ和Kafka是两种非常流行的消息队列系统&#xff0c;但它们的设计哲学、架构特点和适用场景存在显著差异。对比如下。 1、架构设计 RabbitMQ&#xff1a; 基AMQP协议&#xff1a;RabbitMQ是基于AMQP&#xff08;高级消息队列协议&#xff09;构建的&#xff0c;支持多…

玻璃样式的登录界面

AI越来越火了,我们想要不被淘汰就得主动拥抱。推荐一个人工智能学习网站,通俗易懂,风趣幽默,最重要的屌图甚多,忍不住分享一下给大家。点击跳转到网站 先看样式: 源码: <div class="wrapper">

Python数据可视化(够用版):懂基础 + 专业的图表抛给Tableau等专业绘图工具

我先说说文章标题中的“够用版”啥意思&#xff0c;为什么这么写。 按照我个人观点&#xff0c;在使用Python进行数据分析时&#xff0c;我们有时候肯定要结合到图表去进行分析&#xff0c;去直观展现数据的规律和特定&#xff0c;那么我们肯定要做一些简单的可视化&#xff0…

物联网网关Web服务器--CGI开发实例BMI计算

本例子通一个计算体重指数的程序来演示Web服务器CGI开发。 硬件环境&#xff1a;飞腾派开发板&#xff08;国产E2000处理器&#xff09; 软件环境&#xff1a;飞腾派OS&#xff08;Phytium Pi OS&#xff09; 硬件平台参考另一篇博客&#xff1a;国产化ARM平台-飞腾派开发板…

HTML新春烟花

系列文章 序号目录1HTML满屏跳动的爱心&#xff08;可写字&#xff09;2HTML五彩缤纷的爱心3HTML满屏漂浮爱心4HTML情人节快乐5HTML蓝色爱心射线6HTML跳动的爱心&#xff08;简易版&#xff09;7HTML粒子爱心8HTML蓝色动态爱心9HTML跳动的爱心&#xff08;双心版&#xff09;1…