当前位置: 首页 > news >正文

深入剖析 C++ STL 中的 std::list 容器

基本介绍

在 C++ 标准库(STL)中,std::list 是一个基于双向链表实现的序列容器。它与 std::vectorstd::deque 等连续存储容器不同,提供了在序列中高效插入和删除元素的能力,尤其是在序列中间位置操作时优势明显。


1. std::list 的底层原理

std::list 是由一组双向链表节点组成,每个节点包含:

  • 元素数据本身

  • 指向前一个节点的指针(prev

  • 指向后一个节点的指针(next

整个链表通过节点指针串联起来,头节点的 prev 和尾节点的 next 通常指向特殊的哨兵节点或 nullptr

结构示意

nullptr <- [Node1] <-> [Node2] <-> [Node3] -> nullptr

链表不保证元素在内存上的连续存储,每个节点单独分配内存。


2. 主要接口和用法

#include <list>
#include <iostream>int main() {std::list<int> lst = {1, 2, 3};// 头部插入lst.push_front(0);// 尾部插入lst.push_back(4);// 插入到指定位置(通过迭代器)auto it = std::next(lst.begin(), 2);lst.insert(it, 99);// 遍历for (auto val : lst) {std::cout << val << " ";}// 输出: 0 1 99 2 3 4// 删除元素lst.remove(99);// 清空lst.clear();return 0;
}

常用接口

  • push_front / push_back / emplace_front / emplace_back:头尾插入

  • pop_front / pop_back:头尾删除

  • insert:在指定位置插入元素

  • erase:删除指定位置元素

  • remove / remove_if:删除满足条件的元素

  • splice:将另一个链表的部分或全部节点移动到当前链表中(无需复制,效率极高)

  • 双向迭代器支持,允许双向遍历


3. 性能特征与对比

操作std::liststd::vector备注
插入/删除头尾O(1)头部 O(n),尾部 O(1)
插入/删除中间O(1) (有迭代器)O(n)list不需移动元素
随机访问不支持(无 operator[]O(1)list只能顺序访问
内存占用较大(节点指针额外开销)较小,连续内存
缓存局部性影响访问效率

std::list 适合频繁中间插入/删除,且不需要随机访问的场景。


4. 典型使用场景

  • 需要频繁在序列中间插入、删除元素,且已知具体位置的迭代器(如链表实现的任务队列)

  • 实现算法时需要快速拆分、合并链表(splice 功能)

  • 保持迭代器或引用稳定,插入删除时不会使其他元素迭代器失效(与 vector 不同)


5. 高级用法与优化建议

5.1 利用 splice 高效合并链表

splicestd::list 独有且非常高效的操作。它允许将另一个链表的节点直接接入当前链表,避免拷贝和内存分配。

std::list<int> a = {1, 2, 3};
std::list<int> b = {4, 5, 6};// 将b的全部节点接入a的末尾,b变为空链表
a.splice(a.end(), b);

5.2 避免不必要的内存分配

每个节点都单独分配内存,频繁插入大量元素时可能导致性能瓶颈。可以考虑:

  • 批量插入,减少频繁的调用

  • 在性能要求极高时,考虑自定义内存池

5.3 迭代器有效性保证

std::list 插入和删除不会使其他节点的迭代器失效,适合要求迭代器长时间稳定的算法。

5.4 避免误用

  • 不要用 std::list 做需要随机访问的场景

  • 不要为了“感觉好”就盲目使用链表,很多时候 std::vector 更优


6. 其他常用成员函数

size():返回元素个数
empty():判断是否为空
assign(n, val):赋值n个val
remove(val):删除所有等于val的元素
unique():去除连续重复元素
reverse():反转链表
sort():排序

7. 示例:LRU缓存

#include <list>
#include <unordered_map>
using namespace std;class LRUCache {
public:LRUCache(int capacity) : cap(capacity) {}int get(int key) {auto it = mp.find(key);if (it == mp.end()) return -1;cache.splice(cache.begin(), cache, it->second);return it->second->second;}void put(int key, int value) {auto it = mp.find(key);if (it != mp.end()) {it->second->second = value;cache.splice(cache.begin(), cache, it->second);} else {if (cache.size() == cap) {mp.erase(cache.back().first);cache.pop_back();}cache.emplace_front(key, value);mp[key] = cache.begin();}}private:int cap;list<pair<int, int>> cache;unordered_map<int, list<pair<int, int>>::iterator> mp;
};

8. 总结

  • std::list 是双向链表实现,支持高效插入删除,迭代器稳定

  • 牺牲了内存局部性和随机访问能力,不适合频繁随机访问

  • 适合需要频繁中间操作或合并拆分链表的复杂算法

  • 使用时要结合具体需求,避免滥用导致性能下降

  • 利用高级接口如 splice 可实现高效链表操作

http://www.lryc.cn/news/618044.html

相关文章:

  • 机器学习-决策树(DecisionTree)
  • conda一键配置python开发环境
  • .NET Core MVC中CSHTML
  • 在 Rocky Linux 9.2 上使用 dnf 安装 Docker 全流程详解
  • 嵌入式硬件中AI硬件设计方法与技巧
  • 跨平台、低延迟、可嵌入:实时音视频技术在 AI 控制系统中的进化之路
  • day23|前端学习三件套
  • JavaScript Const的基础使用
  • 爬虫与数据分析实战
  • 爬虫和数据分析相结合案例
  • 介绍一下jQuery的AJAX异步请求
  • android 换肤框架详解2-LayoutInflater源码解析
  • 【Linux文件操作】文件操作系统调用
  • 机器学习之DBSCAN
  • Linux中DNS系统搭建与配置指南(配实验步骤与注释)
  • GO学习记录三
  • 【网络运维】Linux:常见 Web 服务器
  • 对自己的 app 进行分析, 诊断,审视
  • FPGA+护理:跨学科发展的探索(二)
  • Python day 41
  • AVS Video Converter视频转换与编辑工具深度评测
  • 什么是电网谐波?
  • PyCharm(2025.1.3.1)绑定 Conda 环境
  • 一篇文章解决Unity没有添加模块选项的问题
  • Android.mk教程
  • 深入解析Windows系统下UDP绑定失败的原理与系统级解决方案
  • Java AI生成长篇小说的实用
  • 算法基础 1
  • 为什么TEXT不区分大小写,而BLOB严格区分?
  • redis笔记(二)