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

news2025/4/9 10:07:05

在 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前插入10
        cout << "After insert, list: ";
        for (int i : lt) {
            cout << i << " ";
        }
        cout << endl;

        lt.erase(it);  // 删除元素3
        cout << "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);  // 缩小容器大小为3
    cout << "调整大小后,列表的大小: " << 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到lt1
    cout << "After merge, lt1: ";
    for (int i : lt1) {
        cout << i << " ";
    }
    cout << endl;

    lt1.reverse();  // 逆置lt1
    cout << "After reverse, lt1: ";
    for (int i : lt1) {
        cout << i << " ";
    }
    cout << endl;

    list<int> lt3 = { 7, 8, 9 };
    lt1.assign(lt3.begin(), lt3.end());  // 用lt3的内容替换lt1
    cout << "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 };

    // 合并两个list
    list1.merge(list2);
    cout << "After merging, list1: ";
    for (int i : list1) {
        cout << i << " ";
    }
    cout << endl;

    // 反转list1
    list1.reverse();
    cout << "After reversing, list1: ";
    for (int i : list1) {
        cout << i << " ";
    }
    cout << endl;

    return 0;
}

 

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

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

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

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

相关文章

按键切换LCD显示后,显示总在第二阶段,而不在第一阶段的问题

这是一个密码锁的程序&#xff0c;当在输入密码后&#xff0c;原本是要重置密码&#xff0c;但是程序总是在输入密码正确后总是跳转置设置第二个密码&#xff0c;而第一个密码总是跳过。 不断修改后&#xff0c; 解决方法 将if语句换成switch语句&#xff0c;这样就可以分离程序…

护网蓝初面试题

《网安面试指南》https://mp.weixin.qq.com/s/RIVYDmxI9g_TgGrpbdDKtA?token1860256701&langzh_CN 5000篇网安资料库https://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247486065&idx2&snb30ade8200e842743339d428f414475e&chksmc0e4732df793fa3bf39…

C++11: 智能指针

C11: 智能指针 &#xff08;一&#xff09;智能指针原理1.RAll2.智能指针 (二)C11 智能指针1. auto_ptr2. unique_ptr3. shared_ptr4. weak_ptr &#xff08;三&#xff09;shared_ptr中存在的问题std::shared_ptr的循环引用 &#xff08;四&#xff09;删除器&#xff08;五&a…

从零实现本地大模型RAG部署

1. RAG概念 RAG&#xff08;Retrieval-Augmented Generation&#xff09;即检索增强生成&#xff0c;是一种结合信息检索与大型语言模型&#xff08;大模型&#xff09;的技术。从外部知识库&#xff08;如文档、数据库或网页&#xff09;中实时检索相关信息&#xff0c;并将其…

【Linux系统篇】:探索文件系统原理--硬件磁盘、文件系统与链接的“三体宇宙”

✨感谢您阅读本篇文章&#xff0c;文章内容是个人学习笔记的整理&#xff0c;如果哪里有误的话还请您指正噢✨ ✨ 个人主页&#xff1a;余辉zmh–CSDN博客 ✨ 文章所属专栏&#xff1a;Linux篇–CSDN博客 文章目录 一.认识硬件--磁盘物理存储结构1.存储介质类型2.物理存储单元3…

Tracing the thoughts of a large language model 简单理解

Tracing the thoughts of a large language model 这篇论文通过电路追踪方法(Circuit Tracing)揭示了大型语言模型Claude 3.5 Haiku的内部机制,其核心原理可归纳为以下几个方面: 1. 方法论核心:归因图与替换模型 替换模型(Replacement Model) 使用跨层转码器(CLT)将原…

OpenCV边缘检测技术详解:原理、实现与应用

概述 边缘检测是计算机视觉和图像处理中最基本也是最重要的技术之一&#xff0c;它通过检测图像中亮度或颜色急剧变化的区域来识别物体的边界。边缘通常对应着场景中物体的物理边界、表面方向的变化或深度不连续处。 分类 OpenCV提供了多种边缘检测算法&#xff0c;下面我们介…

BN 层做预测的时候, 方差均值怎么算

✅ 一、Batch Normalization&#xff08;BN&#xff09;回顾 BN 层在训练和推理阶段的行为是不一样的&#xff0c;核心区别就在于&#xff1a; 训练时用 mini-batch 里的均值方差&#xff0c;预测时用全局的“滑动平均”均值方差。 &#x1f9ea; 二、训练阶段&#xff08;Trai…

JS 其他事件类型

页面加载 事件 window.addEvent() window.addEventListener(load,function(){const btn document.querySelector(button)btn.addEventListener(click,function(){alert(按钮)})})也可以给其他标签加该事件 HTML加载事件 找html标签 也可以给页面直接赋值

AI Agent设计模式五:Orchestrator

概念 &#xff1a;中央任务调度中枢 ✅ 优点&#xff1a;全局资源协调&#xff0c;确保任务执行顺序❌ 缺点&#xff1a;单点故障风险&#xff0c;可能成为性能瓶颈 import operator import osfrom langchain.schema import SystemMessage, HumanMessage from langchain_opena…

MySQL基础 [三] - 数据类型

目录 数据类型分类 ​编辑 数值类型 tinyint bit 浮点类型 float decimal 字符串类型 char varchar varchar和char的比较和选择 日期和时间类型 enum和set enum类型 set类型 enum和set的类型查找 数据类型分类 数值类型 tinyint TINYINT[(M)] [UNSIGNED]是 …

不用训练,集成多个大模型产生更优秀的输出

论文标题 Collab: Controlled Decoding using Mixture of Agents for LLM Alignment 论文地址 https://arxiv.org/pdf/2503.21720 作者背景 JP摩根&#xff0c;马里兰大学帕克分校&#xff0c;普林斯顿大学 动机 大模型对齐&#xff08;alignment&#xff09;的主要目的…

随笔1 认识编译命令

1.认识编译命令 1.1 解释gcc编译命令: gcc test1.cpp -o test1 pkg-config --cflags --libs opencv 命令解析&#xff1a; gcc&#xff1a;GNU C/C 编译器&#xff0c;用于编译C/C代码。 test1.cpp&#xff1a;源代码文件。 -o test1&#xff1a;指定输出的可执行文件名为t…

Hyperlane 框架路由功能详解:静态与动态路由全掌握

Hyperlane 框架路由功能详解&#xff1a;静态与动态路由全掌握 Hyperlane 框架提供了强大而灵活的路由功能&#xff0c;支持静态路由和动态路由两种模式&#xff0c;让开发者能够轻松构建各种复杂的 Web 应用。本文将详细介绍这两种路由的使用方法。 静态路由&#xff1a;简单…

铰链损失函数 Hinge Loss和Keras 实现

一、说明 在为了了解 Keras 深度学习框架的来龙去脉&#xff0c;本文介绍铰链损失函数&#xff0c;然后使用 Keras 实现它们以进行练习并了解它们的行为方式。在这篇博客中&#xff0c;您将首先找到两个损失函数的简要介绍&#xff0c;以确保您在我们继续实现它们之前直观地理解…

瑞数信息发布《BOTS自动化威胁报告》,揭示AI时代网络安全新挑战

近日&#xff0c;瑞数信息正式发布《BOTS自动化威胁报告》&#xff0c;力求通过全景式观察和安全威胁的深度分析&#xff0c;为企业在AI时代下抵御自动化攻击提供安全防护策略&#xff0c;从而降低网络安全事件带来的影响&#xff0c;进一步增强业务韧性和可持续性。 威胁一&am…

FLV格式:流媒体视频的经典选择

FLV格式&#xff1a;流媒体视频的经典选择 FLV&#xff08;Flash Video&#xff09;格式曾经是流媒体视频的主力军&#xff0c;在互联网视频的早期时代广泛应用于视频网站和多媒体平台。凭借其高效的压缩和较小的文件体积&#xff0c;FLV成为了许多视频内容创作者和平台的首选…

需求分析-用例图绘制、流程图绘制

第一&#xff0c;引论 需求分析是开发的第一步&#xff0c;也是我个人认为最重要的一步。 技术难题的克服&#xff0c;甚至在我心里&#xff0c;还要排在需求分析后面。 如果需求分析做好了&#xff0c;数据库就更容易建立&#xff0c;数据库建好了&#xff0c;业务逻辑写起…

Windows安装 PHP 8 和mysql9,win下使用phpcustom安装php8.4.5和mysql9

百度搜索官网并下载phpcustom&#xff0c;然后启动环境&#xff0c;点击网站管理 里面就有php8最新版&#xff0c;可以点mysql设置切mysql9最新版&#xff0c;如果你用最新版无法使用&#xff0c;说明你的php程序不支持最新版的mysql MySQL 9.0 引入了一些新的 SQL 模式和语法变…

http://noi.openjudge.cn/_2.5基本算法之搜索_1804:小游戏

文章目录 题目深搜代码宽搜代码深搜数据演示图总结 题目 1804:小游戏 总时间限制: 1000ms 内存限制: 65536kB 描述 一天早上&#xff0c;你起床的时候想&#xff1a;“我编程序这么牛&#xff0c;为什么不能靠这个赚点小钱呢&#xff1f;”因此你决定编写一个小游戏。 游戏在一…