STL:list

文章目录

  • 标准库中的list
    • list的构造
    • list的迭代器
    • list的容量
    • list的访问
    • list的修改
  • list的迭代器失效
  • list的反向迭代器
  • list 与 vector的对比

标准库中的list

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

list的构造

在这里插入图片描述

Example:

#include <iostream>
using namespace std;
#include <list>
#include <vector>// list的构造
void TestList1()
{list<int> l1;                         // 构造空的l1list<int> l2(4, 100);                 // l2中放4个值为100的元素list<int> l3(l2.begin(), l2.end());  // 用l2的[begin(), end())左闭右开的区间构造l3list<int> l4(l3);                    // 用l3拷贝构造l4// 以数组为迭代器区间构造l5int array[] = { 16,2,77,29 };list<int> l5(array, array + sizeof(array) / sizeof(int));// 列表格式初始化C++11list<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;
}

list的迭代器

list的迭代器类型是一个自定义类型,包含了指向结点的指针,重载了*,->,++,``–,==,!=`等运算符。

在使用时可以简单理解为指向结点的指针。

Example:

#include <iostream>
using namespace std;
#include <list>
#include <vector>// 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;
}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;
}

list的容量

在这里插入图片描述

可以看到,相比于stringvectorlist不支持reserveshink_to_fit等接口,因为链表的底层并不是一块连续的空间,每次插入都需要开辟新的空间,所以不必提前开空间,删除同理。不过list支持了resizeclear等接口,使用较少。

list的访问

在这里插入图片描述

前文已提到,list不支持随机访问,又因为list是双向循环链表,所以可以获取头部元素和尾部元素。

list的修改

在这里插入图片描述

相比于stringvectorlist提供了头插和头删,这也是由于list的底层空间是不连续的有关,元素之间通过指针建立联系,删除头部元素不会导致后续元素的移动,所以list提供了头插和头删,同时还有insert。这些接口在stringvector中要么没有提供,要么不提倡使用,因为效率实在低下。

Example:

#include <iostream>
using namespace std;
#include <list>
#include <vector>// 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,头部插入0L.push_back(4);L.push_front(0);PrintList(L);// 删除list尾部节点和头部节点L.pop_back();L.pop_front();PrintList(L);
}// 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()
{// 用数组来构造listint 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;
}

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的反向迭代器

通过前面例子知道,反向迭代器的++就是正向迭代器的–,反向迭代器的–就是正向迭代器的++,因此反向迭 代器的实现可以借助正向迭代器,即:反向迭代器内部可以包含一个正向迭代器,对正向迭代器的接口进行 包装即可。

template<class Iterator>
class ReverseListIterator
{// 注意:此处typename的作用是明确告诉编译器,Ref是Iterator类中的类型,而不是静态成员变量// 否则编译器编译时就不知道Ref是Iterator中的类型还是静态成员变量// 因为静态成员变量也是按照 类名::静态成员变量名 的方式访问的
public:typedef typename Iterator::Ref Ref;typedef typename Iterator::Ptr Ptr;typedef ReverseListIterator<Iterator> Self;
public://// 构造ReverseListIterator(Iterator it): _it(it){}//// 具有指针类似行为Ref operator*(){Iterator temp(_it);--temp;return *temp;}Ptr operator->(){return &(operator*());}//// 迭代器支持移动Self& operator++(){--_it;return *this;}Self operator++(int){Self temp(*this);--_it;return temp;}Self& operator--(){++_it;return *this;}Self operator--(int){Self temp(*this);++_it;return temp;}//// 迭代器支持比较bool operator!=(const Self& l)const{return _it != l._it;}bool operator==(const Self& l)const{return _it == l._it;}Iterator _it;
}

list 与 vector的对比

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

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

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

相关文章

电子抄表系统:当代能源管理的创新

1.界定与基本原理 电子抄表系统是一种利用通讯网技术&#xff0c;如wifi网络、物联网技术或有线连接&#xff0c;全自动收集并解决电磁能、水、气等公共事业表计数据信息解决方案。它取代了传统人工抄水表方法&#xff0c;提升了数据可靠性和质量。 2.功能和优点 -实时监控系…

【android】设置背景图片

改变值&#xff0c;可显示zai在 在theves下面的两个value都要增加名字代码 <item name"windowActionBar">false</item><item name"android:windowNoTitle">true</item><item name"android:windowFullscreen">tru…

西门子学习笔记6 - TCP通讯

1、主站设置 1、添加两个PLC在网络组态进行链接在一起&#xff0c;使用tcp链接 2、设置主站IP地址为&#xff1a;192.168.1.1 3、添加TSEND_C功能块 4、设置功能块参数连接 5、设置如下所示&#xff08;连接参数设置&#xff09; 6、设置如下所示&#xff08;连接块参数设置&a…

数字化高炉:高炉炼铁厂可视化解决方案

图扑高炉炼铁厂可视化系统通过实时监控和数据分析&#xff0c;全面展示高炉生产各环节的运行状态、温度和压力等关键参数。实现精准控制和决策支持&#xff0c;提高生产效率&#xff0c;减少能耗和污染&#xff0c;确保生产过程的安全和稳定。

生信软件21 - 多线程拆分NCBI-SRA文件工具pfastq-dump

在使用NCBI 工具fastq-dump拆分SRA文件时&#xff0c;拆分速度慢&#xff0c; fastq-dump拆分参数说明&#xff1a; –split-spot: 将双端测序分为两份&#xff0c;存放在同一个文件中–split-files: 将双端测序分为两份&#xff0c;存放在不同的文件&#xff0c;但是对于一方…

华为进军越野车领域 | 百能云芯

在最近召开的2024未来汽车发展峰会上&#xff0c;华为智能汽车解决方案BU的领军人物余承东分享了一项引人注目的计划&#xff1a;华为正积极评估进军硬派越野车型市场的可能性。 余承东明确表示&#xff0c;若决定进入该领域&#xff0c;华为不会简单地复制传统越野车型如奔驰G…

svg完成鼠标样式并使用

本次分享的是通过svg标签实现的鼠标样式&#xff0c;并在页面中进行使用的整个过程&#xff0c;最后还会分享快速制作svg的简单方式。 如有改进的方法或者发现错误也可以在评论区留言啊。 一、鼠标的svg样式 1.小飞机型 <svg width"32" height"32" xml…

【python】OpenCV—Merge Image

文章目录 np.hstack / np.vstackSlicecv2.addWeighted自定义渐变式叠加cv2.bitwise_not / cv2.bitwise_and / cv2.add np.hstack / np.vstack 利用 numpy 的 hstack 和 vstack&#xff0c;对图片进行拼接 import cv2 import numpy as nph, w 256,256 img1 cv2.resize(cv2.i…

Pico4 MR Unity零基础开发之开启MR透视

一、新建场景&#xff1a;SeethroughScene 1、新建场景。 二、添加 XR 摄像机进行设置 1、在 Hierarchy 窗口中&#xff0c;右击默认添加的 Main Camera&#xff0c;然后点击 Delete 将其删除。 2、点击 > XR > XR Origin (VR)&#xff0c;将 XR Origin 添加至场景 3、…

[leetcode hot 150]第七十题,爬楼梯(动态规划)

题目&#xff1a; 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 爬到第 n 阶楼梯的方法数量等于爬到第 n-1 阶和第 n-2 阶的方法数量之和,即: f(n) f(n-1) f(n-2) 边界条件 还需要考虑边界…

【调试笔记-20240602-Linux-在 OpenWRT-23.05 上配置 frps 与 frpc 之间使用 TLS 进行传输】

调试笔记-系列文章目录 调试笔记-20240602-Linux-在 OpenWRT-23.05 上配置 frps 与 frpc 之间使用 TLS 进行传输 文章目录 调试笔记-系列文章目录调试笔记-20240602-Linux-在 OpenWRT-23.05 上配置 frps 与 frpc 之间使用 TLS 进行传输 前言一、调试环境操作系统&#xff1a;O…

Ubuntu 22.04安装cuda及Pytorch教程

文章目录 1、安装显卡驱动2、安装CUDA3、安装cuDNN4、安装pyTorch5、卸载CUDA参考资料 在PyTorch中使用CUDA&#xff0c;需要确保安装的PyTorch版本与你的CUDA版本兼容&#xff0c; 且正确安装了匹配GPU的CUDA Toolkit。以下是在PyTorch中使用CUDA的一般步骤&#xff1a; 检查C…

Padstack制作贴片和通孔焊盘

Padstack制作贴片和通孔焊盘 一、贴片焊盘制作 先选择SMD Pin&#xff0c;下面的pad geometry根据需求选择&#xff0c;一般是Circle和Rectangle&#xff0c;然后选择单位&#xff0c;mm制。 然后点击Design Layers&#xff0c;只需要修改Regular Pad常规焊盘就行&#xff0c…

七天进阶elasticsearch[two]

批量保存 批量保存是通过_bulk API来实现的 请求方式 post 请求地址 _bulk 通过_bulk操作文档,一般至少有两行参数 第一行用于确定要干什么(插入,修改还是删除) 第二行才是操作的数据; 当然以上是标准操作,也可以不遵循标准操作,使用不同的请求方式来完成 批量保存demo…

浅谈申请小程序地理位置权限的正确打开方式

小程序地理位置接口有什么功能&#xff1f; 这篇内容会教大家如何快速申请“获取当前的地理位置&#xff08;onLocationChange&#xff09;”接口&#xff0c;以便帮助大家顺利开通接口。以下内容是本人经历了多次的申请经历得出来的经验&#xff0c;来之不易&#xff0c;望大家…

【Python】让我们来生成二维码吧

准备操作 安装qrcode包&#xff1a;pip install qrcode[pil] 安装Pillow包&#xff1a;pip install Pillow 代码 import qrcode import hashlibdef generate_filename(url):data_bytes url.encode("utf-8")file_name hashlib.sha256(data_bytes).hexdigest()re…

图卷积网络原理及实践

图神经网络 (GNN) 是深度学习领域最吸引人且发展最快的架构之一。作为旨在处理图结构数据的深度学习模型&#xff0c;GNN 具有非凡的多功能性和强大的学习能力。 在各种类型的 GNN 中&#xff0c;图卷积网络 (GCN) 已成为最流行且应用最广泛的模型。GCN 具有创新性&#xff0c…

现在有一个生产计划,甲乙丙3个品类共16个产品,生产时间6天,每天甲品类可以生产1张单,乙3张,丙1张,请用MySQL写出H列的效果

现在有一个生产计划&#xff0c;甲乙丙3个品类共16个产品&#xff0c;生产时间6天&#xff0c;每天甲品类可以生产1张单&#xff0c;乙3张&#xff0c;丙1张&#xff0c;请用MySQL写出H列的效果吗&#xff1f; 最终展示结果要求为&#xff1a; 品类产品生产时间开始生产时间…

Android开机动画压缩包zip,自制开机动画(基于Android10.0.0-r41)

文章目录 Android开机动画压缩包zip&#xff0c;自制开机动画1.Android加载压缩包原理2.自制开机动画 Android开机动画压缩包zip&#xff0c;自制开机动画 1.Android加载压缩包原理 这里有个md文件我们看下 核心部分, 首先要创建一个文件叫做desc.txt&#xff0c;这是规定的…

【AI】你要的U-KAN来了

every blog every motto: You can do more than you think. https://blog.csdn.net/weixin_39190382?typeblog 0. 前言 U-KAN来了&#xff0c;快是真的快的&#xff0c;上个月才出的KAN&#xff0c;不得不说快。 先占个坑&#xff0c;有时间细看。 下面放上摘要 1. 正文 …