C++基础笔记(三)链表list

一、数据结构说明
  1. list
    std::list 是一种双向链表 (doubly linked list),其底层数据结构是互不连续的节点。
    • 刷题要点
      • 任何位置 进行元素的插入和删除都非常高效,时间复杂度为 O(1)。
      • 不支持随机访问 (如 list[i]),只能通过迭代器顺序访问,访问第 N 个元素时间复杂度为 O(N)。
      • 在需要频繁在序列中间进行增删 操作,且不需要随机访问 的场景下,listvectordeque 更具优势。
二、常见使用方法

std::list 核心使用

C++ 复制代码
#include <list>
#include <algorithm> // 部分操作可能需要,但list有自带的sort

// 常见构造
std::list<int> l;                 // 空 list
std::list<int> l3 = {1,2,3,4};    // 列表初始化

// 查看属性
l.size();      // 元素个数,O(N) (可能,视具体实现)
l.empty();     // 是否为空,O(1)
// 注意:list 没有 capacity() 接口,因为是链表结构,按需分配。

// 改变大小
l.resize(n);          // 改变 size:变大时填充默认值,变小时移除多余元素。
l.clear();            // 清空所有元素。

// 元素增删改查
l.push_back(x);       // 尾部添加,O(1)
l.pop_back();         // 删除尾部元素,O(1)
l.push_front(x);      // 头部添加,O(1)
l.pop_front();        // 头部删除,O(1)
l.insert(it, x);      // 在迭代器 it 位置插入,O(1)
l.erase(it);          // 擦除 it(返回下一个元素迭代器),O(1)

// 遍历
// list 不支持随机访问,只能用迭代器或范围for循环
for (const auto &x : l) { /* ... */ }
for (auto it = l.begin(); it != l.end(); ++it) { /* ... */ }

std::list 特殊操作

C++ 复制代码
// 排序
l.sort();                         // 默认升序,list自带的排序方法,O(N log N)
l.sort(std::greater<int>());      // 降序

// 合并与拼接
l.merge(other_list);              // 将 other_list 合并到当前 list (要求两者都已排序),other_list 变空。
l.splice(it, other_list);         // 将 other_list 的所有元素移动到当前 list 的 it 位置,other_list 变空。

// 移除
l.remove(value);                  // 移除所有值为 value 的元素。
l.remove_if(predicate);           // 移除所有满足 predicate 条件的元素。
l.unique();                       // 移除连续重复的元素(list 必须已排序)。
l.reverse();                      // 反转 list。
三、底层实现
  1. list
    std::list 的底层是一个双向循环链表 。每个节点包含数据、指向前一个节点的指针和指向后一个节点的指针。通常会有一个"哨兵节点"(伪头节点)来简化边界处理。
    • 插入和删除:仅需修改少量指针,时间复杂度为 O(1)。
    • 随机访问:不支持 O(1),需 O(N) 遍历。
    • 内存开销 :每个节点额外的指针存储导致内存占用高于 std::vector
    • 迭代器稳定性:插入和删除元素时,除了被删除元素的迭代器,其他迭代器保持有效。
四、注意事项
  • 选择依据std::list 最适用于需要频繁在序列中间进行插入和删除 ,但不要求随机访问 的场景。如果涉及大量随机访问或内存连续性有要求,应优先考虑 std::vectorstd::deque
  • 排序 :由于不支持随机访问迭代器,std::list 不能使用 std::sort,而必须使用其自带的 sort() 成员函数
  • 内存和性能 :尽管插入删除快,但由于内存不连续,list 的遍历可能比 vector 慢,且每个元素占用更多内存。
  • 迭代器失效list 的迭代器在插入和删除操作时相对稳定,但为了代码清晰和避免潜在问题,建议在操作后更新相关迭代器。
  • 使用场景 :需要频繁在数据结构中进行插入,删除或者合并操作,同时不需要排序或者在插入的时候已经有序。又或者是不确定数据的大小或者内存碎片较多的场景(这种刷题的时候不考虑内存问题,大部分都是时间不够),例如基数排序中的每个桶中的元素(不过一般vector也能实现而且效果更好就是了)。
相关推荐
じ☆冷颜〃5 小时前
分布式系统中网络技术的演进与异构融合架构(HFNA)
笔记·python·物联网·设计模式·架构·云计算
散峰而望8 小时前
【算法竞赛】C++函数详解:从定义、调用到高级用法
c语言·开发语言·数据结构·c++·算法·github
CoderCodingNo8 小时前
【GESP】C++五级真题(贪心思想考点) luogu-B4071 [GESP202412 五级] 武器强化
开发语言·c++·算法
我有一些感想……8 小时前
An abstract way to solve Luogu P1001
c++·算法·ai·洛谷·mlp
郭涤生8 小时前
第十章_信号_《UNIX环境高级编程(第三版)》_笔记
服务器·笔记·unix
QT 小鲜肉8 小时前
【Linux命令大全】001.文件管理之which命令(实操篇)
linux·运维·服务器·前端·chrome·笔记
巧克力味的桃子9 小时前
单链表 - 有序插入并输出学习笔记
笔记·学习
智者知已应修善业9 小时前
【求等差数列个数/无序获取最大最小次大次小】2024-3-8
c语言·c++·经验分享·笔记·算法
..过云雨10 小时前
17-2.【Linux系统编程】线程同步详解 - 条件变量的理解及应用
linux·c++·人工智能·后端
量子炒饭大师10 小时前
Cyber骇客的逻辑节点美学 ——【初阶数据结构与算法】二叉树
c语言·数据结构·c++·链表·排序算法