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

news/2024/11/19 6:41:30/

一、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; //单位mscout << "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.ppmy.cn/news/89208.html

相关文章

Day49【动态规划】121.买卖股票的最佳时机、122.买卖股票的最佳时机II

121.买卖股票的最佳时机 力扣题目链接/文章讲解 视频讲解 动态规划五部曲&#xff01; 1、确定 dp 数组下标及值的含义 先想想本题 dp 应该怎么定义&#xff0c;别忘了之前说的&#xff0c;dp 数组的下标能够表示状态 在股票问题中&#xff0c;某个状态需要描述在某天&…

k8s 弹性伸缩的使用

1.手动扩缩容 编辑一个yaml文件 vi deployment-nginx.yaml apiVersion: apps/v1 kind: Deployment metadata:lables:app: nginxname: nginxnamespace: default spec:replicas: 3selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name:…

opencv_c++学习(十九)

一、图像间的距离变换 三种常用的距离计算方法&#xff1a; 欧式距离这里就不在解释。 街区距离&#xff1a;顾名思义&#xff0c;就类似于城市距离一样&#xff0c;并不是通过两点间的距离&#xff0c;而是我们从一个地点到达另一个地点的路程(横纵坐标差值之和)。 棋盘距离…

torch.distributed.launch多卡多机

torch.distributed.launch命令介绍 我们在训练分布式时候&#xff0c;会使用到 torch.distributed.launch 可以通过命令&#xff0c;来打印该模块提供的可选参数 python -m torch.distributed.launch --help usage: launch.py [-h] [--nnodes NNODES] [--node_rank NODE_RANK]…

SpringMVC详情

JavaEE体系结构包括四层&#xff0c;从上到下分别是应用层、Web层、业务层、持久层。Struts和SpringMVC是Web层的框架&#xff0c;Spring是业务层的框架&#xff0c;Hibernate和MyBatis是持久层的框架。 为什么要使用SpringMVC&#xff1f; 很多应用程序的问题在于处理业务数…

Spring Cloud Feign 是什么?如何使用它来简化 RESTful 调用?

Spring Cloud Feign 是什么&#xff1f;如何使用它来简化 RESTful 调用&#xff1f; 在分布式系统中&#xff0c;服务之间的通信是非常常见的场景。通常情况下&#xff0c;服务之间的通信是通过 RESTful API 实现的。但是&#xff0c;手动编写 RESTful 调用代码非常繁琐&#…

云渲染平台为什么越来越多的效果图公司开始使用?

随着3dmax版本的不断更迭&#xff0c;包括常用的V-Ray渲染器和Corona渲染器的不断更新&#xff0c;室内设计行业对于 效果图的渲染要求越来越高。而要求更高的渲染精度和更真实的渲染效果&#xff0c;所需要付出的代价则是不断增长的参数&#xff0c;这会使渲染一张效果图的时间…

vscode插件推荐

Vuter vue代码高亮区分VueHelper 代码提示vue3-snippets-for-vscode 生成vue3模板vue3-snippets 生成vue模板Vue VSCode Snippets 生成vue模板Vue Language Features (Volar) vue高亮区分Vue 3 Support - All In One 生成vue模板Vue 2 Snippets 生成vue模板vscode-icons 文件图…