【043】解密C++ STL:深入理解并使用 list 容器

解密C++ STL:深入理解并使用list容器

  • 引言
  • 一、list 容器概述
  • 二、list容器常用的API
    • 2.1、构造函数
    • 2.2、数据元素插入和删除操作
    • 2.3、大小操作
    • 2.4、赋值操作
    • 2.5、数据的存取
    • 2.6、list容器的反转和排序
  • 三、使用示例
  • 总结

引言


💡 作者简介:一个热爱分享高性能服务器后台开发知识的博主,目标是通过理论与代码实践的结合,让世界上看似难以掌握的技术变得易于理解与掌握。技能涵盖了多个领域,包括C/C++、Linux、Nginx、MySQL、Redis、fastdfs、kafka、Docker、TCP/IP、协程、DPDK等。
👉
🎖️ CSDN实力新星、CSDN博客专家
👉
🔔 专栏介绍:从零到c++精通的学习之路。内容包括C++基础编程、中级编程、高级编程;掌握各个知识点。
👉
🔔 专栏地址:C++从零开始到精通
👉
🔔 博客主页:https://blog.csdn.net/Long_xu


🔔 上一篇:【042】解密C++ STL:深入理解并使用queue容器

一、list 容器概述

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。

链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。相较于vector的连续线性空间,list就显得负责许多,它的好处是每次插入或者删除一个元素,就是配置或者释放一个元素的空间。因此,list对于空间的运用有绝对的精准,一点也不浪费。而且,对于任何位置的元素插入或元素的移除,list永远是常数时间。List和vector是两个最常被使用的容器。List容器是一个双向链表。

在这里插入图片描述
采用动态存储分配,不会造成内存浪费和溢出链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素链表灵活,但是空间和时间额外耗费较大。

二、list容器常用的API

2.1、构造函数

C++标准库中的列表容器(List Container)是一个双向链表的实现,提供了高效的插入和删除操作。其构造函数的原型如下:

explicit list(const Allocator& alloc = Allocator());
list(size_type count, const T& value, const Allocator& alloc = Allocator());
explicit list(size_type count, const Allocator& alloc = Allocator());
template <class InputIt>
list(InputIt first, InputIt last, const Allocator& alloc = Allocator());
list(const list& other);
list(const list& other, const Allocator& alloc);
list(list&& other) noexcept;
list(list&& other, const Allocator& alloc);

使用示例:

  1. 使用默认构造函数创建空的列表:
std::list<int> myList;
  1. 使用指定元素个数和默认值创建列表:
std::list<int> myList(5, 10); // 创建包含5个值为10的元素的列表
  1. 使用范围内的元素创建列表:
std::vector<int> vec{1, 2, 3, 4, 5};
std::list<int> myList(vec.begin(), vec.end()); // 从vector中的元素创建列表
  1. 复制另一个列表创建新列表:
std::list<int> myList1{1, 2, 3};
std::list<int> myList2(myList1); // 通过复制myList1创建一个新列表
  1. 移动另一个列表创建新列表:
std::list<int> myList1{1, 2, 3};
std::list<int> myList2(std::move(myList1)); // 通过移动myList1创建一个新列表

2.2、数据元素插入和删除操作

  1. 插入操作:
  • push_back:在列表末尾插入一个元素。

    void push_back(const T& value);
    

    示例:

    std::list<int> myList;
    myList.push_back(42);  // 在列表末尾插入值为42的元素
    
  • push_front:在列表开头插入一个元素。

    void push_front(const T& value);
    

    示例:

    std::list<int> myList;
    myList.push_front(42);  // 在列表开头插入值为42的元素
    
  • insert:在指定位置插入一个或多个元素。

    iterator insert(const_iterator pos, const T& value);
    iterator insert(const_iterator pos, size_type count, const T& value);
    

    示例:

    std::list<int> myList{1, 2, 3};
    myList.insert(myList.begin() + 1, 4);         // 在索引1处插入值为4的元素
    myList.insert(myList.end(), 2, 5);            // 在末尾插入两个值为5的元素
    myList.insert(myList.begin(), {6, 7, 8});     // 在开头插入值为6、7、8的元素
    
  1. 删除操作:
  • pop_back:删除列表末尾的一个元素。

    void pop_back();
    

    示例:

    std::list<int> myList{1, 2, 3};
    myList.pop_back();  // 删除列表末尾的元素
    
  • pop_front:删除列表开头的一个元素。

    void pop_front();
    

    示例:

    std::list<int> myList{1, 2, 3};
    myList.pop_front();  // 删除列表开头的元素
    
  • erase:在指定位置或范围内删除一个或多个元素。

    iterator erase(const_iterator pos);
    iterator erase(const_iterator first, const_iterator last);
    

    示例:

    std::list<int> myList{1, 2, 3, 4, 5};
    myList.erase(myList.begin() + 2);                  // 删除索引为2的元素
    myList.erase(myList.begin() + 1, myList.end());    // 删除从索引1到末尾的所有元素
    
  • remove:删除列表中值等于给定值的所有元素。

    void remove(const T& value);
    

    示例:

    std::list<int> myList{1, 2, 3, 2, 4, 2};
    myList.remove(2);   // 删除所有值为2的元素
    
  • clear:清空列表中的所有元素。

    void clear();
    

    示例:

    std::list<int> myList{1, 2, 3, 4, 5};
    myList.clear();     // 清空列表中的所有元素
    

2.3、大小操作

下面是list容器大小操作的函数原型和使用示例:

  1. size:返回列表中元素的个数。
size_type size() const;

示例:

std::list<int> myList{1, 2, 3, 4, 5};
size_t size = myList.size();   // 获取列表中元素的个数,结果为5
  1. empty:检查列表是否为空。
bool empty() const;

示例:

std::list<int> myList;
bool isEmpty = myList.empty();    // 检查列表是否为空,结果为true
  1. max_size:返回列表可能包含的最大元素数量。
size_type max_size() const;

示例:

std::list<int> myList;
size_t maxSize = myList.max_size();   // 获取列表可能包含的最大元素数量
  1. resize:改变列表的大小,可以增加或减少元素的数量。
void resize(size_type count);
void resize(size_type count, const value_type& value);
  • 第一个版本将列表的大小更改为指定的count值,如果count小于当前大小,则删除多余的元素;如果count大于当前大小,则在末尾插入默认构造的元素。新添加的元素将使用T的默认构造函数创建。
  • 第二个版本将列表的大小更改为指定的count值,并使用value作为新插入元素的值。

示例1:

std::list<int> myList{1, 2, 3, 4, 5};
myList.resize(8);    // 将列表的大小更改为8,多出的3个元素将使用int的默认构造函数创建,结果为 {1, 2, 3, 4, 5, 0, 0, 0}

示例2:

std::list<int> myList{1, 2, 3, 4, 5};
myList.resize(10, 42);   // 将列表的大小更改为10,多出的5个元素将使用值为42的元素填充,结果为 {1, 2, 3, 4, 5, 42, 42, 42, 42, 42}

2.4、赋值操作

list容器提供了几种赋值操作函数:assign、operator=重载和swap。

  1. assign:用新元素替换列表中的内容。
void assign(size_type count, const T& value);
template<class InputIterator>
void assign(InputIterator first, InputIterator last);
  • 第一个版本将列表的内容替换为count个值为value的元素。
  • 第二个版本将列表的内容替换为范围[first, last)中的元素,可以是另一个容器或迭代器表示的序列。

示例1:

std::list<int> myList;
myList.assign(5, 42);   // 将列表赋值为5个值为42的元素,结果为 {42, 42, 42, 42, 42}

示例2:

std::list<int> myList1{1, 2, 3};
std::list<int> myList2{4, 5, 6};
myList1.assign(myList2.begin(), myList2.end());   // 将列表赋值为myList2的内容,结果为 {4, 5, 6}
  1. operator=重载:使用一个列表替换另一个列表的内容。
list& operator=(const list& other);

示例:

std::list<int> myList1{1, 2, 3};
std::list<int> myList2{4, 5, 6};
myList1 = myList2;   // 将myList1的内容替换为myList2的内容,结果为 {4, 5, 6}
  1. swap:交换两个列表的内容。
void swap(list& other);

示例:

std::list<int> myList1{1, 2, 3};
std::list<int> myList2{4, 5, 6};
myList1.swap(myList2);   // 交换myList1和myList2的内容,结果为 myList1: {4, 5, 6},myList2: {1, 2, 3}

2.5、数据的存取

list容器提供了两个用于数据存取的函数:front和back。

  1. front:返回第一个元素的引用。
reference front();
const_reference front() const;
  • 第一个版本返回对第一个元素的引用,可以用于修改元素的值。
  • 第二个版本在常量列表上返回对第一个元素的引用,不能用于修改元素的值。

示例:

std::list<int> myList{1, 2, 3, 4, 5};
int& firstElement = myList.front();     // 获取第一个元素的引用
int firstValue = myList.front();        // 获取第一个元素的值firstElement = 10;                      // 修改第一个元素的值
std::cout << myList.front() << std::endl;   // 输出结果为 10
  1. back:返回最后一个元素的引用。
reference back();
const_reference back() const;
  • 第一个版本返回对最后一个元素的引用,可以用于修改元素的值。
  • 第二个版本在常量列表上返回对最后一个元素的引用,不能用于修改元素的值。

示例:

std::list<int> myList{1, 2, 3, 4, 5};
int& lastElement = myList.back();       // 获取最后一个元素的引用
int lastValue = myList.back();          // 获取最后一个元素的值lastElement = 20;                       // 修改最后一个元素的值
std::cout << myList.back() << std::endl;    // 输出结果为 20

通过使用front和back函数,您可以访问和修改list容器中的首尾元素。但是,在空列表上调用front或back函数是错误的,因为列表不包含任何元素时是无效的操作,可能引发未定义的行为。

2.6、list容器的反转和排序

list容器提供了两个函数用于反转排序:reverse和sort。以下是它们的函数原型和使用示例:

  1. reverse:将列表中的元素按相反的顺序重新排列。
void reverse();
  • 该函数会更改列表中元素的顺序,将第一个元素置于最后一个元素的位置,第二个元素置于倒数第二个位置,依此类推。

示例:

std::list<int> myList{1, 2, 3, 4, 5};
myList.reverse();   // 反转列表中元素的顺序for (const auto& num : myList) {std::cout << num << " ";   // 输出结果为 5 4 3 2 1
}
  1. sort:对列表中的元素进行排序。
void sort();
  • 该函数会按升序对列表中的元素进行排序,默认使用 < 运算符进行比较。

示例:

std::list<int> myList{5, 2, 4, 1, 3};
myList.sort();   // 对列表中元素进行升序排序for (const auto& num : myList) {std::cout << num << " ";   // 输出结果为 1 2 3 4 5
}

通过调用reverse函数,可以将list容器中的元素按相反的顺序重新排列。而通过调用sort函数,则可以对列表中的元素进行排序。

三、使用示例

以下是一个使用list容器的简单案例:

#include <iostream>
#include <list>int main() {std::list<int> myList;// 向列表中添加元素myList.push_back(1);myList.push_back(2);myList.push_back(3);// 遍历并输出列表中的元素for (const auto& num : myList) {std::cout << num << " ";}std::cout << std::endl;// 在特定位置插入元素auto it = myList.begin();++it;  // 移动迭代器到第二个位置myList.insert(it, 4);// 遍历并输出更新后的列表for (const auto& num : myList) {std::cout << num << " ";}std::cout << std::endl;// 从列表中删除指定元素myList.remove(2);// 遍历并输出更新后的列表for (const auto& num : myList) {std::cout << num << " ";}std::cout << std::endl;// 清空列表myList.clear();// 检查列表是否为空if (myList.empty()) {std::cout << "列表为空" << std::endl;}return 0;
}

上述代码展示了使用list容器的一些常见操作:

  • 使用push_back函数向列表末尾添加元素。
  • 使用循环遍历列表并输出其中的元素。
  • 使用insert函数在指定位置插入元素。
  • 使用remove函数删除指定元素。
  • 使用clear函数清空列表中的所有元素。
  • 使用empty函数检查列表是否为空。

总结

List容器是C++标准库中的一种线性容器,它提供了双向链表的实现。

  1. 特点:

    • 双向链表:list容器使用双向链表实现,每个节点都包含一个指向前驱节点和后继节点的指针,因此在插入和删除操作上具有较好的性能。
    • 动态大小:list容器的大小可以根据需要动态调整,不会有预设上限。
    • 插入和删除效率高:由于双向链表的特性,list容器对于插入和删除操作具有较高的效率。插入和删除元素时不会产生元素的移动操作。
    • 迭代器稳定性:list容器支持稳定的迭代器,即当进行插入和删除操作时,仅影响相关节点,不会使其他迭代器失效。
  2. 使用方法:

    • 头文件:<list>
    • 声明容器:std::list<T> myList;,其中T为存储在列表中的元素类型。
    • 添加元素:使用push_back函数将元素添加到列表末尾,使用push_front函数将元素添加到列表头部。
    • 遍历列表:可以使用范围-based for循环或迭代器遍历访问列表中的元素。
    • 插入和删除元素:使用insert函数在指定位置插入元素,使用erase函数删除指定位置的元素。
    • 反转和排序:可以使用reverse函数反转列表中元素的顺序,使用sort函数对列表进行排序。
    • 其他操作:list容器还提供了诸如访问第一个元素、最后一个元素、大小、清空列表等操作。
  3. 适用场景:

    • 需要频繁进行插入和删除操作,而不关注随机访问性能。
    • 需要稳定的迭代器,避免插入和删除操作导致迭代器失效。
    • 需要支持高效地在任意位置插入和删除元素,而不需要连续内存空间的特性。
  4. 注意点:

  • list容器的迭代器是双向迭代器,不支持+2,但支持++。
  • STL提供的算法只支持随机访问迭代器,而list容器的迭代器是双向迭代器,所以sort算法不支持list迭代器。如果要排序,可以使用list类模板提供的sort函数。

list容器是一个非常有用的线性容器,适用于需要频繁进行插入和删除操作,并且需要稳定迭代器的场景。它通过双向链表的实现,在插入和删除操作上具有较好的性能,并提供了丰富的操作函数来满足各种需求。
在这里插入图片描述

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

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

相关文章

2023年深圳杯数学建模D题基于机理的致伤工具推断

2023年深圳杯数学建模 D题 基于机理的致伤工具推断 原题再现&#xff1a; 致伤工具的推断一直是法医工作中的热点和难点。由于作用位置、作用方式的不同&#xff0c;相同的致伤工具在人体组织上会形成不同的损伤形态&#xff0c;不同的致伤工具也可能形成相同的损伤形态。致伤…

7D透明屏的市场应用广泛,在智能家居中有哪些应用表现?

7D透明屏是一种新型的显示技术&#xff0c;它能够实现透明度高达70%以上的显示效果。这种屏幕可以应用于各种领域&#xff0c;如商业广告、展览展示、智能家居等&#xff0c;具有广阔的市场前景。 7D透明屏的工作原理是利用光学投影技术&#xff0c;将图像通过透明屏幕投射出来…

Talk | 南洋理工大学博士后研究员李祥泰:基于Transformer的视觉分割模型总结、回顾与展望

​ 本期为TechBeat人工智能社区第517期线上Talk&#xff01; 北京时间7月27日(周四)20:00&#xff0c;南洋理工大学博士后研究员—李祥泰的Talk已经准时在TechBeat人工智能社区开播了&#xff01; 他与大家分享的主题是: “基于Transformer的视觉分割模型总结、回顾与展望”&am…

C#多线程

C#多线程 C#多线程是C#学习中必不可少的知识&#xff0c;在实际开发中也能有效的提升用户体验&#xff0c;和程序性能。 文章目录 C#多线程前言一、什么是线程、什么是进程、什么是协程&#xff1f;协程优点缺点 线程优点缺点&#xff1a; 进程优点缺点&#xff1a; 二、C# 中…

使用Spring Boot实现Redis键过期回调功能

使用Spring Boot实现Redis键过期回调功能 当使用Redis作为缓存或数据存储的时候&#xff0c;有时候需要在键过期时执行一些特定的操作&#xff0c;比如清除相关数据或发送通知。在Spring Boot中&#xff0c;可以通过实现RedisMessageListener接口来实现Redis键过期回调功能。下…

基于“RWEQ+”集成技术在土壤风蚀模拟与风蚀模数估算、变化归因分析中的实践应用及SCI论文撰写

查看原文>>>基于“RWEQ”集成技术在土壤风蚀模拟与风蚀模数估算、变化归因分析中的实践应用及SCI论文撰写 土壤风蚀是一个全球性的环境问题。中国是世界上受土壤风蚀危害最严重的国家之一&#xff0c;土壤风蚀是中国干旱、半干旱及部分湿润地区土地荒漠化的首要过程。…

B2B企业如何选择CRM系统?

CRM软件的优势在于简化业务流程&#xff0c;实现企业的降本增效。越来越多的B2B企业通过CRM为业务赋能&#xff0c;B2B企业如何快速找到适合公司业务的CRM系统&#xff1f;总的来说就是根据企业自身业务而量身打造的一套系统。 1.整理业务需求 B2B企业首先要考虑是业务痛点&a…

MySQL绿色安装和配置

1、 从地址http://dev.mysql.com/downloads/mysql/中选择windows的版本下载。 2、 mysql各个版本的简介 &#xff08;1&#xff09; MySQL Community Server 社区版本&#xff0c;开源免费&#xff0c;但不提供官方技术支持。 &#xff08;2&#xff09; MySQL Enterprise Ed…

Spring MVC

一、什么是MVC MVC就是一种思想&#xff0c;而Spring MVC是对MVC思想的具体实现 MVC是Model View Controller的所缩写&#xff0c;是一种软件架构模式&#xff0c;它将软件系统Fenwick墨香&#xff0c;视图和控制器三个基本部分。 Model&#xff1a;是应用程序中用于处理应用…

7.27 Qt

制作简易小闹钟 Timer.pro QT core gui texttospeechgreaterThan(QT_MAJOR_VERSION, 4): QT widgetsCONFIG c11# The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # dep…

Cisco 路由器配置管理

大多数网络中断的最常见原因是错误的配置更改。对网络设备配置的每一次更改都伴随着造成网络中断、安全问题甚至性能下降的风险。计划外更改使网络容易受到意外中断的影响。 Network Configuration Manager 网络更改和配置管理 &#xff08;NCCM&#xff09;解决方案&#xff…

Python(四十五)二层循环中的break和continue

❤️ 专栏简介&#xff1a;本专栏记录了我个人从零开始学习Python编程的过程。在这个专栏中&#xff0c;我将分享我在学习Python的过程中的学习笔记、学习路线以及各个知识点。 ☀️ 专栏适用人群 &#xff1a;本专栏适用于希望学习Python编程的初学者和有一定编程基础的人。无…

C#之泛型

目录 一、概述 二、C#中的泛型 继续栈的示例 三、泛型类 &#xff08;一&#xff09;声明泛型类 &#xff08;二&#xff09;创建构造类型 &#xff08;三&#xff09;创建变量和实例 &#xff08;四&#xff09;比较泛型和非泛型栈 四、类型参数的约束 &#xff08;一…

elementUI --- el-select 下拉框 日历 级联选择

element UI 组件库中的 select 选择器 中下拉列表的样式&#xff0c;在页面渲染的时候&#xff0c;总是渲染为仅次于body级别的div &#xff0c;这样子覆盖样子会影响全局其他的select选择器下拉框样式&#xff0c;试图通过给el-select加父标签来覆盖&#xff0c;然而并没有卵用…

【FAQ】关于无法判断和区分用户与地图交互手势类型的解决办法

一&#xff0e; 问题描述 当用户通过缩放手势、平移手势、倾斜手势和旋转手势与地图交互&#xff0c;控制地图移动改变其可见区域时&#xff0c;华为地图SDK没有提供直接获取用户手势类型的API。 二&#xff0e; 解决方案 华为地图SDK的地图相机有提供CameraPosition类&…

哈希表及其模拟实现

文章目录 一、解决哈希冲突1.1闭散列1.1.1线性探测1.1.2二次探测 1.2开散列 二、模拟实现哈希表三、HashMap源码的一些相关内容 哈希&#xff08;散列&#xff09;方法&#xff1a;构造一种存储结构&#xff0c;通过某种函数使元素的存储位置与它的关键码之间能够建立 一 一 映…

【JavaWeb】Tomcat底层机制和Servlet运行原理

&#x1f384;欢迎来到dandelionl_的csdn博文&#xff0c;本文主要讲解Java web中Tomcat底层机制和Servlet的运行原理的相关知识&#x1f384; &#x1f308;我是dandelionl_&#xff0c;一个正在为秋招和算法竞赛做准备的学生&#x1f308; &#x1f386;喜欢的朋友可以关注一…

HCIA实验二

实验要求&#xff1a; 1.R2为ISP&#xff0c;只能配置IP 2.R1-R2之间为HDLC封装 3.R2-R3之间为PPP封装&#xff0c;pap认证&#xff0c;R2为主认证方 4.R2-R4之间为PPP封装&#xff0c;chap认证&#xff0c;R2为主认证方 5.R1、R2、R3构建MGRE&#xff0c;仅R1的IP地址固定…

【Nginx12】Nginx学习:HTTP核心模块(九)浏览器缓存与try_files

Nginx学习&#xff1a;HTTP核心模块&#xff08;九&#xff09;浏览器缓存与try_files 浏览器缓存在 Nginx 的 HTTP 核心模块中其实只有两个简单的配置&#xff0c;这一块也是 HTTP 的基础知识。之前我们就一直在强调&#xff0c;学习 Nginx 需要的就是各种网络相关的基础知识&…

AndroidStudio设计一个计算器

界面设计 activity_calcuator.xml 设计&#xff1a; <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:app"http://schemas.android.com/apk/res-auto&qu…