C++ STL 详解 ——list 的深度解析与实践指南

在 C++ 的标准模板库(STL)中,list作为一种重要的序列式容器,以其独特的双向链表结构和丰富的操作功能,在许多编程场景下发挥着关键作用。深入理解list的特性与使用方法,能帮助开发者编写出更高效、灵活的代码。

一、list 的结构特点

list的底层是双向链表结构,这意味着每个元素都存储在独立的结点中,每个结点通过指针分别指向其前一个元素和后一个元素。这种结构使得list在任意位置进行插入和删除操作时,都能在常数时间内完成,效率极高。例如,当需要在链表中间插入一个新元素时,只需修改相关指针的指向,无需像数组那样移动大量元素。同时,双向链表的结构还支持前后双向迭代,方便从两个方向遍历容器。

forward_list相比,list的双向链表结构虽然在功能上更强大,但也带来了一些额外的开销。由于每个结点都需要额外的空间来存储前后指针,对于存储类型较小的元素,这些额外空间的占用可能会对内存使用产生较大影响。而且,与数组和向量不同,list不支持随机访问,不能通过下标直接访问特定位置的元素,这在一些需要频繁随机访问的场景下会带来不便。

二、list 的使用方法

(一)定义方式

list提供了多种灵活的定义方式。可以构造一个空容器,如list<int> lt1;,用于后续动态添加元素。也能创建一个包含指定数量且值相同的元素的容器,像list<int> lt2(10, 2);,这里的lt2就包含了 10 个值为 2 的元素。通过拷贝构造,能复制已有容器的内容,list<int> lt3(lt2);lt2的内容复制到lt3中。此外,还可以利用迭代器或数组区间来初始化list,例如:

#include <iostream>
#include <list>
#include <string>
using namespace std;int main() {list<int> lt1;list<int> lt2(10, 2);list<int> lt3(lt2);string s("hello world");list<char> lt4(s.begin(), s.end()); int arr[] = { 1, 2, 3, 4, 5 };int sz = sizeof(arr) / sizeof(int);list<int> lt5(arr, arr + sz); // 打印各个list的内容cout << "lt1: ";for (int i : lt1) {cout << i << " ";}cout << endl;cout << "lt2: ";for (int i : lt2) {cout << i << " ";}cout << endl;cout << "lt3: ";for (int i : lt3) {cout << i << " ";}cout << endl;cout << "lt4: ";for (char c : lt4) {cout << c << " ";}cout << endl;cout << "lt5: ";for (int i : lt5) {cout << i << " ";}cout << endl;return 0;
}

 

(二)插入和删除操作

  1. 头部操作push_frontpop_front函数分别用于在容器头部插入和删除元素。这在需要频繁在头部添加或删除数据的场景下非常实用,比如实现一个栈结构时,就可以利用list的这些操作。
#include <iostream>
#include <list>
using namespace std;int main() {list<int> lt;lt.push_front(1);lt.push_front(2);cout << "After push_front, list: ";for (int i : lt) {cout << i << " ";}cout << endl;lt.pop_front();cout << "After pop_front, list: ";for (int i : lt) {cout << i << " ";}cout << endl;return 0;
}

  1. 尾部操作push_backpop_back函数则用于在容器尾部进行插入和删除操作,在实现队列结构时经常会用到。
#include <iostream>
#include <list>
using namespace std;int main() {list<int> lt;lt.push_back(1);lt.push_back(2);cout << "After push_back, list: ";for (int i : lt) {cout << i << " ";}cout << endl;lt.pop_back();cout << "After pop_back, list: ";for (int i : lt) {cout << i << " ";}cout << endl;return 0;
}

  1. 指定位置操作insert函数支持在指定迭代器位置进行多种插入操作,包括插入一个数、插入多个相同值的数以及插入一段迭代器区间。erase函数可以删除指定迭代器位置的元素或指定迭代器区间内的所有元素。在使用这些函数时,通常会结合<algorithm>头文件中的find函数来定位要操作的位置。
#include <iostream>
#include <list>
#include <algorithm>
using namespace std;int main() {list<int> lt = { 1, 2, 3, 4, 5 };auto it = find(lt.begin(), lt.end(), 3);if (it != lt.end()) {lt.insert(it, 10);  // 在找到的元素3前插入10cout << "After insert, list: ";for (int i : lt) {cout << i << " ";}cout << endl;lt.erase(it);  // 删除元素3cout << "After erase, list: ";for (int i : lt) {cout << i << " ";}cout << endl;}return 0;
}

 

(三)迭代器使用

list的迭代器分为正向迭代器和反向迭代器。通过begin函数获取容器中第一个元素的正向迭代器,end函数获取最后一个元素后一个位置的正向迭代器,利用正向迭代器可以从前往后遍历容器。而rbeginrend函数分别返回容器中最后一个元素的反向迭代器和第一个元素前一个位置的反向迭代器,方便从后往前遍历容器。

#include <iostream>
#include <list>
using namespace std;int main() {list<int> lt = { 1, 2, 3, 4, 5 };// 正向迭代器遍历cout << "Forward iteration: ";for (auto it = lt.begin(); it != lt.end(); ++it) {cout << *it << " ";}cout << endl;// 反向迭代器遍历cout << "Reverse iteration: ";for (auto it = lt.rbegin(); it != lt.rend(); ++it) {cout << *it << " ";}cout << endl;return 0;
}

 

(四)元素获取与大小控制

使用frontback函数可以轻松获取list容器中的第一个和最后一个元素。size函数用于获取容器中当前元素的个数,resize函数能够调整容器的大小,根据传入参数的不同,实现扩大或缩小容器。empty函数用于判断容器是否为空,clear函数则可以清空容器中的所有元素。


#include <iostream>
#include <list>
using namespace std;int main() {list<int> lt = { 1, 2, 3, 4, 5 };cout << "前元素: " << lt.front() << endl;cout << "返回元素: " << lt.back() << endl;cout << "列表大小: " << lt.size() << endl;lt.resize(3);  // 缩小容器大小为3cout << "调整大小后,列表的大小: " << lt.size() << endl;if (lt.empty()) {cout << "列表为空" << endl;}else {cout << "列表不是空的" << endl;}lt.clear();if (lt.empty()) {cout << "清除后,列表为空" << endl;}else {cout << "清除后,列表不为空" << endl;}return 0;
}

 

(五)其他操作函数

  1. 排序与拼接sort函数可以将容器中的数据默认排为升序,在对数据顺序有要求时十分便捷。splice函数用于两个list容器之间的拼接,有多种拼接方式,可以将整个容器、某个元素或指定区间的数据拼接到另一个容器的指定位置,但要注意被拼接的数据会从原容器中移除。
#include <iostream>
#include <list>
using namespace std;int main() {list<int> lt1 = { 3, 1, 2 };list<int> lt2 = { 6, 4, 5 };lt1.sort();cout << "After sorting lt1: ";for (int i : lt1) {cout << i << " ";}cout << endl;lt1.splice(lt1.end(), lt2);  // 将lt2拼接到lt1的末尾cout << "After splice, lt1: ";for (int i : lt1) {cout << i << " ";}cout << endl;return 0;
}

  1. 元素删除与去重remove函数用于删除容器中特定值的元素,remove_if函数则可以删除满足特定条件的元素,unique函数用于删除容器中连续的重复元素,不过在使用unique函数去重前,通常需要先对容器内元素进行排序。
#include <iostream>
#include <list>
#include <algorithm>
using namespace std;bool isEven(int num) {return num % 2 == 0;
}int main() {list<int> lt = { 1, 2, 2, 3, 4, 4, 5 };lt.remove(2);  // 删除值为2的元素cout << "After remove 2, list: ";for (int i : lt) {cout << i << " ";}cout << endl;lt.remove_if(isEven);  // 删除偶数元素cout << "After remove_if, list: ";for (int i : lt) {cout << i << " ";}cout << endl;lt = { 1, 2, 2, 3, 3, 3 };lt.sort();lt.unique();  // 去重cout << "After unique, list: ";for (int i : lt) {cout << i << " ";}cout << endl;return 0;
}

  1. 合并与其他操作merge函数用于将一个有序list容器合并到另一个有序list容器中,合并后容器依然保持有序。reverse函数用于逆置容器中元素的位置,assign函数可以用新内容替换容器的当前内容,swap函数用于交换两个容器的内容。
#include <iostream>
#include <list>
using namespace std;int main() {list<int> lt1 = { 1, 3, 5 };list<int> lt2 = { 2, 4, 6 };lt1.merge(lt2);  // 合并lt2到lt1cout << "After merge, lt1: ";for (int i : lt1) {cout << i << " ";}cout << endl;lt1.reverse();  // 逆置lt1cout << "After reverse, lt1: ";for (int i : lt1) {cout << i << " ";}cout << endl;list<int> lt3 = { 7, 8, 9 };lt1.assign(lt3.begin(), lt3.end());  // 用lt3的内容替换lt1cout << "After assign, lt1: ";for (int i : lt1) {cout << i << " ";}cout << endl;list<int> lt4 = { 10, 11, 12 };lt1.swap(lt4);  // 交换lt1和lt4的内容cout << "After swap, lt1: ";for (int i : lt1) {cout << i << " ";}cout << endl;return 0;
}

 

三、应用场景

  1. 数据频繁插入和删除:在实现一些需要频繁进行插入和删除操作的数据结构时,如优先队列、缓存管理等,list的高效插入和删除特性使其成为理想选择。例如,在缓存管理中,当有新数据进入缓存或旧数据被淘汰时,list能够快速调整数据顺序。
#include <iostream>
#include <list>
using namespace std;class Cache {
private:list<int> cacheList;int capacity;public:Cache(int cap) : capacity(cap) {}void access(int data) {for (auto it = cacheList.begin(); it != cacheList.end(); ++it) {if (*it == data) {cacheList.erase(it);cacheList.push_front(data);return;}}if (cacheList.size() >= capacity) {cacheList.pop_back();}cacheList.push_front(data);}void printCache() {for (int i : cacheList) {cout << i << " ";}cout << endl;}
};int main() {Cache cache(3);cache.access(1);cache.access(2);cache.access(3);cache.printCache();cache.access(2);cache.printCache();cache.access(4);cache.printCache();return 0;
}

  1. 链表相关算法实现:由于list本身就是基于双向链表结构,在实现链表相关的算法,如链表的反转、合并等时,直接使用list容器可以简化代码编写,并且能充分利用其内置的操作函数。
#include <iostream>
#include <list>
using namespace std;int main() {list<int> list1 = { 1, 2, 3 };list<int> list2 = { 4, 5, 6 };// 合并两个listlist1.merge(list2);cout << "After merging, list1: ";for (int i : list1) {cout << i << " ";}cout << endl;// 反转list1list1.reverse();cout << "After reversing, list1: ";for (int i : list1) {cout << i << " ";}cout << endl;return 0;
}

 

  1. 内存管理优化:在一些对内存使用有严格要求的场景下,如果数据元素之间的顺序关系较为灵活,且不需要频繁随机访问,list的动态内存分配和释放特性可以有效避免内存碎片问题,提高内存利用率。

list作为 C++ STL 中的重要容器,以其独特的双向链表结构和丰富的操作函数,在众多编程场景中都有着不可替代的作用。开发者在实际编程中,应根据具体需求,合理选择使用list,充分发挥其优势,提升程序的性能和质量。

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

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

相关文章

GenerationMixin概述

类 类名简单说明GenerateDecoderOnlyOutput继承自 ModelOutput&#xff0c;适用于非束搜索方法的解码器-only模型输出类。GenerateEncoderDecoderOutput继承自 ModelOutput&#xff0c;适用于非束搜索方法的编码器-解码器模型输出类。GenerateBeamDecoderOnlyOutput继承自 Mod…

【备赛】蓝桥杯嵌入式实现led闪烁

原理 由于蓝桥杯的板子带有锁存器&#xff0c;并且与lcd屏幕有冲突&#xff0c;所以这个就成了考点。 主要就是用定时器来实现&#xff0c;同时也要兼顾lcd的冲突。 一、处理LCD函数 首先来解决与lcd屏幕冲突的问题&#xff0c;把我们所有用到的lcd函数改装一下。 以下是基…

C++ 并发性能优化实战:提升多线程应用的效率与稳定性

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家、CSDN平台优质创作者&#xff0c;获得2024年博客之星荣誉证书&#xff0c;高级开发工程师&#xff0c;数学专业&#xff0c;拥有高级工程师证书&#xff1b;擅长C/C、C#等开发语言&#xff0c;熟悉Java常用开发技术&#xff0c…

Python----计算机视觉处理(Opencv:道路检测之车道线拟合)

完整版&#xff1a; Python----计算机视觉处理&#xff08;Opencv:道路检测完整版&#xff1a;透视变换&#xff0c;提取车道线&#xff0c;车道线拟合&#xff0c;车道线显示&#xff09; 一、获取左右车道线的原始位置 导入模块 import cv2 import numpy as np from matplot…

优选算法的妙思之流:分治——归并专题

专栏&#xff1a;算法的魔法世界 个人主页&#xff1a;手握风云 目录 一、归并排序 二、例题讲解 2.1. 排序数组 2.2. 交易逆序对的总数 2.3. 计算右侧小于当前元素的个数 2.4. 翻转对 一、归并排序 归并排序也是采用了分治的思想&#xff0c;将数组划分为多个长度为1的子…

C语言查漏补缺:基础篇

1.原理 C语言是一门编译型计算机语言&#xff0c;要编写C代码&#xff0c;C源代码文本文件本身无法直接执行&#xff0c;必须通过编译器翻译和链接器的链接&#xff0c;生成二进制的可执行文件&#xff0c;然后才能执行。这里的二进制的可执行文件就是我们最终要形成的可执行程…

TPS入门DAY02 服务器篇

1.创建空白插件 2.导入在线子系统以及在线steam子系统库 MultiplayerSessions.uplugin MultiplayerSessions.Build.cs 3.创建游戏实例以及初始化会话创建流程 创建会话需要的函数&#xff0c;委托&#xff0c;委托绑定的回调&#xff0c;在线子系统接口绑定某一个委托的控制其…

产品经理课程

原型工具 一、土耳其机器人 这个说法来源于 1770 年出现的一个骗局&#xff0c;一个叫沃尔夫冈冯肯佩伦&#xff08;Wolfgang von Kempelen&#xff09;的人为了取悦奥地利女皇玛丽娅特蕾莎&#xff08;Maria Theresia&#xff09;&#xff0c;“制造”了一个会下国际象棋的机…

nginx中的limit_req 和 limit_conn

在 Nginx 中&#xff0c;limit_req 和 limit_conn 是两个用于限制客户端请求的指令&#xff0c;它们分别用于限制请求速率和并发连接数。 limit_req limit_req 用于限制请求速率&#xff0c;防止客户端发送过多请求影响服务器性能。它通过 limit_req_zone 指令定义一个共享内存…

基于winform的串口调试助手

目录 一、串口助手界面设计 1.1 串口配置 1.2 接收配置 1.3 发送配置 1.4 接收窗口和发送窗口 1.5 状态显示窗口 1.6 串口通讯控件 二、程序编写 2.1 端口号自动识别并显示在端口号下拉框 功能说明&#xff1a; 2.2 波特率下拉框显示 2.3 数据位下拉框显示 2.4 校…

Docker基础2

如需转载&#xff0c;标记出处 本次我们将下载一个 Docker 镜像&#xff0c;从镜像中启动容器 上一章&#xff0c;安装 Docker 时&#xff0c;获得两个主要组件&#xff1a; Docker 客户端 Docker 守护进程&#xff08;有时称为“服务器”或“引擎”&#xff09; 守护进程实…

Rocketmq2

一、生产者端防丢失 1. 发送方式选择 同步发送&#xff1a;使用 send() 方法&#xff0c;等待 Broker 确认响应&#xff08;SendResult&#xff09;&#xff0c;确保消息已成功发送。异步发送&#xff1a;使用 sendAsync() 方法并设置回调函数&#xff0c;处理发送成功 / 失败…

RabbitMQ详解,RabbitMQ是什么?架构是怎样的?

目录 一,RabbitMQ是什么? 二,RabbitMQ架构 2.1 首先我们来看下RabbitMQ里面的心概念Queue是什么? 2.2 交换器Exchange 2.3 RabbitMQ是什么? 2.4 重点看下优先级队列是什么? 三,RabbitMQ集群 3.1 普通集群模式 3.2 镜像队列集群 一,RabbitMQ是什么? 假设我们程序…

【一步步开发AI运动APP】六、运动计时计数能调用

之前我们为您分享了【一步步开发AI运动小程序】开发系列博文&#xff0c;通过该系列博文&#xff0c;很多开发者开发出了很多精美的AI健身、线上运动赛事、AI学生体测、美体、康复锻炼等应用场景的AI运动小程序&#xff1b;为了帮助开发者继续深耕AI运动领域市场&#xff0c;今…

MySQL——DQL的多表查询

一、交叉连接 标准语法&#xff1a;select * from 表1 cross join 表2 where 表1.公共列 表2.公共列; 简单语法&#xff1a;select * from 表1 , 表2 where 表1.公共列 表2.公共列; 公共列&#xff1a;两张表具有相同含义的列&#xff0c;不是列名一样。 …

【Linux内核】如何更加优雅阅读Linux内核源码(vscode)

1. 前言 因为已经习惯在Ubuntu下进行嵌入式工作开发&#xff0c;但Linux源码在Source Insight下进行阅读&#xff0c;一直很苦恼Linux/Windows来回切换的开发方式&#xff0c;当前发现可以通过 vscode clangd(扩展组件) 方式进行更好的内核源码阅读。 2. 环境 操作系统&…

21.OpenCV获取图像轮廓信息

OpenCV获取图像轮廓信息 在计算机视觉领域&#xff0c;识别和分析图像中的对象形状是一项基本任务。OpenCV 库提供了一个强大的工具——轮廓检测&#xff08;Contour Detection&#xff09;&#xff0c;它能够帮助我们精确地定位对象的边界。这篇博文将带你入门 OpenCV 的轮廓…

LETTERS(DFS)

【题目描述】 给出一个rowcolrowcol的大写字母矩阵&#xff0c;一开始的位置为左上角&#xff0c;你可以向上下左右四个方向移动&#xff0c;并且不能移向曾经经过的字母。问最多可以经过几个字母。 【输入】 第一行&#xff0c;输入字母矩阵行数RR和列数SS&#xff0c;1≤R,S≤…

Day2-2:前端项目uniapp壁纸实战

再在wallpaper新建一个目录components 在components下新建组件common-title 记得点击创建同名目录 在index加 <view class"select"><common-title></common-title></view> 图片换了下&#xff0c;原来的有点丑&#xff0c;图片可按自己喜欢…

其他 vector 操作详解(四十)

介绍 除去向 vector 添加元素&#xff08;如 push_back&#xff09;之外&#xff0c;vector 还提供了许多其他操作&#xff0c;这些操作大多与 string 的操作类似。通过掌握这些操作&#xff0c;我们可以方便地查询、修改和比较 vector 中的元素&#xff0c;从而构建灵活、高效…