【STL模版库】list介绍及使用 {inserterase的迭代器失效问题,vector_sort VS list_sort,list的其他接口函数}

news2025/1/13 7:48:16

一、list的介绍

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

在这里插入图片描述


二、list的使用

对于list的使用这里就不做过多介绍了。因为STL设计的相似性,各种容器的使用方法都是类似的。

大家可以参考网站cplusplus.com中对list的使用手册,快速上手使用。

下面只介绍一些相对特殊和list专有的方法:

2.1 insert & erase

void Test1(){    
 int arr[] = {1,2,3,4,5};
  list<int> lt(arr, arr+5);      
  list<int>::iterator it = lt.begin();    
  while(it != lt.end())    
  {    
    //在偶数前连续插入其10倍和100倍   
    if(*it % 2 == 0)    
    {    
      lt.insert(it,*it*10); 
      lt.insert(it,*it*100);    
    }    
    ++it;    
  }    
                           
  for(int e : lt)       
  {                      
    cout << e << " ";          
  }                             
  cout <<endl;    
} 

运行结果:

在这里插入图片描述

结论:

  • 由于链表中每个元素都存储在互不相关的独立节点中插入无需挪动数据,且不需要扩容;不存在迭代器移位和野指针的问题。因此list::insert不会造成迭代器失效。
  • list::insert返回新插入的第一个节点的迭代器。
void Test2(){
 int arr[] = {1,2,2,3,4,4,5,6,6,6};
  list<int> lt(arr, arr+10);  
  list<int>::iterator it = lt.begin();
  while(it != lt.end())
  {                                                                                                             
  	//删除链表中所有的偶数
   	//if(*it % 2 == 0) //错误写法,程序崩溃
   	//{
		//lt.erase(it);
	//}
	//++it;
	if(*it % 2 == 0) //正确写法
   	{
		it = lt.erase(it);
	}
	else
	{
		++it;
	}
  }
  
  for(int e : lt)
  {
    cout << e << " ";
  }
  cout <<endl;
}

运行结果:

在这里插入图片描述

结论:

  • list::erase删除节点并释放空间,此时的迭代器成了野指针,++it访问野指针程序崩溃。因此list::erase会造成迭代器失效。
  • list::erase返回最后删除节点的下一个节点的迭代器,可以通过接收返回值实现连续删除。

2.2 list::sort

在这里插入图片描述

  • 默认升序排序,要排降序传greater()对象。

  • 注意:list不能使用<algorithm>算法库中的sort。由于list不能通过下标访问的原因(快速排序不能进行三数取中等操作),<algorithm>库中提供的sort函数并不能排序链表。因此list类模版中定义了list专用的成员函数list::sort可以对链表进行排序,list::sort底层使用归并排序实现

vector_sort VS list_sort

void Test5(){
  list<int> lt;
  vector<int> v1;
  srand(time(nullptr));
  size_t k = 1000000;
  for(size_t i = 0; i<1000000; ++i)
  {       
    int e = rand();
    lt.push_back(e);
    v1.push_back(e);
  }
  
  //list_sort:
  double begin1 = clock();
  lt.sort();
  double end1 = clock();

  //vector_sort:
  double begin2 = clock();
  sort(v1.begin(), v1.end());
  double end2 = clock();

  //vector_copy_sort:
  vector<int> v2(k);
  double begin3 = clock();
  copy(lt.begin(), lt.end(), v2.begin());
  sort(v2.begin(), v2.end());
  copy(v2.begin(), v2.end(), lt.begin());
  double end3 = clock();
    
  cout << "list_sort: " << (end1-begin1)/CLOCKS_PER_SEC*1000 << endl; //单位ms
  cout << "vector_sort: " << (end2-begin2)/CLOCKS_PER_SEC*1000 <<endl;
  cout << "vector_copy_sort: " << (end3-begin3)/CLOCKS_PER_SEC*1000 <<endl;
}

运行结果:

在这里插入图片描述

总结:

  • vector sort<algorithm>底层采用快速排序算法 O(N*logN),list::sort 底层采用归并排序算法 O(N*logN)。两种算法的效率相差不大。
  • 但由于vector存储空间连续的特点,访存速度较快。因此对于少量数据vector_sort和list_sort的效率相差不大。但对于数据量较大的排序vector_sort的效率更高
  • 在数据量很大的情况下,甚至将list数据拷贝到vector中进行排序后再拷贝回来(vector_copy_sort)都比单纯的list_sort更高。

2.3 其他接口

splice

在这里插入图片描述

注意:“转移”不是拷贝而是移动,即转移数据后原链表中的数据丢失。对于链表而言这样的移动数据操作非常高效,只需要改变节点间指针的链接关系即可。


advance

在这里插入图片描述

功能:advance是一个函数模版可以向后移动任意类型的迭代器,包括list。

注意:

  1. 不同于string和vector这类顺序存储容器的迭代器(底层实际是指针),list迭代器没有重载operator+operator-不能使用+或-直接移动迭代器。必须通过调用advance函数实现“随机访问”。

  2. 注意使用advance实现的“随机访问”加引号,底层任需要遍历n个节点,效率低。

  3. 使用advance必须包含头文件<iterator>,并且展开std命名空间。


distance

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G4yPhyuO-1684806066112)(C:\Users\zty85\AppData\Roaming\Typora\typora-user-images\image-20230521112340506.png)]

功能:distance是一个函数模版,用于计算任意类型迭代器之间(左闭右开区间)的元素个数,包括list。

提示:使用distance必须包含头文件<iterator>,并且展开std命名空间。


remove & remove_if

在这里插入图片描述

功能:删除链表中与指定值相等的所有节点,如果节点的数据是自定义类型,在释放空间之前还会调用析构函数。

在这里插入图片描述

功能:功能与remove类似,只不过参数是一个返回值为bool的一元函数指针,用于条件判断。如果满足条件就从链表中删除。


unique

在这里插入图片描述

注意:需要在使用前先对链表进行排序。

功能:

  1. 第一个版本用于删除链表中的重复元素;

  2. 第二个版本需传入一个返回值为bool的二元函数指针,用于条件判断。如果前后两个元素满足指定的条件则删除后一个保留前一个。


merge

在这里插入图片描述

注意:需要在使用前先对链表进行排序。

功能:

  1. 第一个版本按值比较归并两个有序链表,归并结束后x为+空。
  2. 第二个版本需要传入指定的比较函数,如果认为第一个参数在其定义的严格弱排序中先于第二个参数,则返回 true,否则返回 false

reverse

在这里插入图片描述

功能:用于逆置链表。

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

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

相关文章

JavaEE(系列10) -- 多线程案例3(定时器)

目录 1. 定时器 2. 标准库中的定时器 3. 实现定时器 3.1 创建带优先级的阻塞队列 3.2 创建MyTask类 3.3 构建schedule方法 3.4 构建timer类中的线程 3.5 思考 1. 定时器 定时器也是软件开发中的一个重要组件. 类似于一个 "闹钟". 达到一个设定的时间之后, 就执行某…

chatgpt赋能Python-python_gauge

Python Gauge: 新一代的测试工具 Python Gauge是一个用于自动化测试的轻量级框架&#xff0c;它具有可扩展性和适应性&#xff0c;特别适合测试大型应用程序。Python Gauge支持多种编程语言包括Python&#xff0c;Java&#xff0c;C#和Ruby&#xff0c;因此可以应对各种情况。…

燃气管网监测系统:解析地下管道安全隐患

地下燃气管道是现代城市能源供应的重要组成部分&#xff0c;它们为居民和工业提供了安全、便利的燃气能源。然而&#xff0c;随着时间的推移&#xff0c;地下燃气管道可能出现安全隐患&#xff0c;如老化、腐蚀、机械损伤等&#xff0c;这可能导致泄漏、爆炸和环境污染等严重后…

Bits, Bytes and Integers——二进制unsigned以及Two-complement表示,十六进制

这篇文章梳理一下Bits, Bytes and Integers——二进制unsigned以及Two-complement表示&#xff0c;十六进制这些事儿。 计算机中所有数据都是用二进制的0和1组成的&#xff0c;直接上知识点。 二进制 Unsigned以及Two-complement 同样的一串二进制数&#xff0c;按照有符号…

chatgpt赋能Python-python_headq

Python heapq模块介绍 简介 heapq模块是Python语言中的一个自带优先队列模块&#xff0c;提供一个堆队列&#xff08;heap queue&#xff09;算法实现。堆是具有以下两个特点的树形数据结构&#xff1a; 父节点的键值总是小于或等于&#xff08;或总是大于或等于&#xff09…

英国VIBRO-METER VM600 CPUM 模块化CPU卡

特征 VM600 CPUM/IOCN机架控制器和通信接口卡对&#xff0c;支持Modbus RTU/TCP或PROFINET&#xff0c;以及前面板显示器使用以太网或RS-232串行连接到运行VM600 MPSx软件的计算机&#xff0c;对VM600机架中的保护卡(MPC4和AMC8)进行“一次性”配置管理前面板显示器&#xff0…

AI日报:“虚拟空间传送系统”能让你在家中七分钟环游世界

&#x1f680; “虚拟空间传送系统”能让你在家中七分钟环游世界 “虚拟空间传送系统”能让你在家中七分钟环游世界&#xff0c;由谷歌地图3D Tiles API和ChatGPT带来沉浸式旅行&#xff1b; 又有人将人生六个月交给ChatGPT进行全球旅行计划&#xff0c;但这也引发人们对于LU…

28所示范性微电子院校占地面积排名,中山大学第一!

01中山大学13725 中山大学简称中大&#xff0c;现有广州、珠海和深圳三校区五校园&#xff0c;占地面积共计13725亩。1924年&#xff0c;孙中山亲手将广州地区多所高校整合创立国立广东大学。1926年定名为国立中山大学。如今该校由1952年院系调整后分设的中山大学和中山医科大学…

爱创科技携UDI解决方案亮相CMEF盛会!

2023年5月14日-17日&#xff0c;第87届中国国际医疗器械博览会&#xff08;简称“CMEF”&#xff09;在上海圆满举行。来自全世界20余个国家和地区品牌代表&#xff0c;近5000家企业参展&#xff0c;千余位业界大咖、意见领袖共聚盛会。 CMEF被业界看作全球医疗器械产业风向标&…

Maven方式构建Spring Boot项目

文章目录 一&#xff0c;创建Maven项目二&#xff0c;添加依赖三&#xff0c;创建入口类四&#xff0c;创建控制器五&#xff0c;运行入口类六&#xff0c;访问Web页面七&#xff0c;修改访问映射路径八&#xff0c;定制启动标语1、创建标语文件2、生成标语字符串3、编辑标语文…

Golang idea panic()中报错解决

本地Golang升级到1.18后&#xff0c;发现原本写的一些代码在Goland中出现了一些红色的波浪线&#xff0c;将鼠标移到错误提示上&#xff0c;有如下的显示&#xff1a; Cannot use err (type error) as the type any 复制 image 源代码&#xff1a; conn, err : listener.Ac…

【操作系统】内存

内存的基础知识 什么是内存&#xff0c;有何作用&#xff1f; 内存可存放数据。 程序执行前需要先放到内存中才能被CPU处理——缓和CPU与硬盘之间的速度矛盾 指令的工作是基于“地址”的&#xff0c;每个地址对应一个数据的存储单元 如何把逻辑地址转换为物理地址&#xff1f…

Linux安装Redis数据库,无需公网IP实现远程连接

文章目录 1. Linux(centos8)安装redis数据库2. 配置redis数据库3. 内网穿透3.1 安装cpolar内网穿透3.2 创建隧道映射本地端口 4. 配置固定TCP端口地址4.1 保留一个固定tcp地址4.2 配置固定TCP地址4.3 使用固定的tcp地址连接 转发自cpolar内网穿透的文章&#xff1a;公网远程连接…

Linux——分析和排查系统故障

个人简介&#xff1a;云计算网络运维专业人员&#xff0c;了解运维知识&#xff0c;掌握TCP/IP协议&#xff0c;每天分享网络运维知识与技能。座右铭&#xff1a;海不辞水&#xff0c;故能成其大&#xff1b;山不辞石&#xff0c;故能成其高。 个人主页&#xff1a;小李会科技的…

分布式事务及Seata 1.6.1案例

文章目录 一、分布式事务二、什么时候需要用到分布式事务三、分布式理论CAP定理BASE理论 四、分布式事务解决方案刚性事务2PC3PC2PC和3PC对比 补偿事务TCC 基于消息队列的最终一致性本地消息表消息事务MQ事务消息和本地消息表对比 各方案常见使用场景总结 五、Seata 1.6.1测试1…

android应用市场的上线流程

国内Android应用市场有很多&#xff0c;各有各的优势&#xff0c;对于开发者而言会在每个市场发布&#xff0c;或者在主要的市场发布后其它应用市场会抓取信息并自动上线App&#xff0c;这也节省开发者上线时间。App上线前首先要申请软件著作权&#xff0c;国内应用市场上线基本…

【GPT科技系列】国内开发者调用openAI-API科技方法

1. 前言 openAI上线7个月了&#xff0c;但是随着openAI的约束越来越多&#xff0c;国内开发者想要使用openai的接口实现开发简直就是难上加难。那真的就没有办法了吗&#xff1f;no no no&#xff0c;CF解决一切不开心~ 2.准备工作 我们需要一个国际域名 注册cloudflare账号 …

OPPO哲库事件 “ 始末 ” ! 集体打哑谜?

1►OPPO哲库解散 2019 年&#xff0c;美国商务部以“科技网络安全”为由&#xff0c;将华为公司及其70家附属公司列入出口管制“实体名单”。与此同时&#xff0c;OPPO 创始人兼 CEO陈明永对外宣布&#xff0c;公司将为未来三年内投入 500 亿元用于前沿技术和深水区技术的探索…

Colab解压压缩包删除非空文件夹的方式

Colaboratory 简称“Colab”&#xff0c;Google Research 团队开发&#xff0c;任何人都可以通过浏览器编写和执行任意 Python 代码&#xff0c;尤其适合机器学习、数据分析、教育目的。Colab 是一种托管式 Jupyter 笔记本服务&#xff0c;用户无需设置&#xff0c;就可直接使用…

【Spring】Spring之publishEvent

观察者模式Spring之publishEvent事件处理 1.使用场景 这个一般什么时候使用&#xff0c;我们一般是在不同的bean直接进行信息传递&#xff0c;比如我们beanA的事件处理完后&#xff0c;需要beanB进行处理一些业务逻辑的时候这种情况就一般可以使用publish-event解决。 可用于…