C++--list


一、list 核心概念

1.1 本质

list 是带头结点的双向循环链表 ,底层节点动态开辟,非连续内存空间 。迭代器是对节点指针的封装(不是原生指针)。

1.2 与 vector 的本质区别

vector list
底层结构 连续空间(动态数组) 带头结点的双向循环链表
迭代器 原

六、list vs vector 完整对比

vector list
底层结构 动态数组,连续空间 带头结点双向循环链表
随机访问 O(1) O(n)
头插/头删 O(n),需搬移所有元素 O(1)
任意位置插入/删除 O(n) O(1)
增容代价 开辟新空间+拷贝+释放旧空间 无增容,每次插入只申请一个节点
空间利用率 高,无额外指针开销 低,每个节点额外存两个指针
缓存利用率 高,连续内存预读友好 低,节点分散在堆中
内存碎片 不易产生内存碎片 小节点频繁申请释放,易产生碎片
迭代器类型 随机访问迭代器 双向迭代器
迭代器底层 原生指针 T* 封装的节点指针
插入时迭代器失效 会(扩容导致) 不会
删除时迭代器失效 当前及之后全部失效 仅被删节点失效
operator[] 支持 不支持(无法随机访问)
reserve/capacity 有 没有
适用场景 高效存储 + 随机访问,少插入删除 大量插入删除,不关心随机访问

七、复习自测问答

Q1:list 的底层结构是什么?

答: 带头结点的双向循环链表。

Q2:list 的迭代器是原生指针吗?

答: 不是。list 的迭代器是对节点指针的封装 (必须支持 ++、-- 等操作跳转到相邻节点,原生指针做不到),而 vector 的迭代器才是原生指针 T*。

Q3:list 插入元素会导致迭代器失效吗?

答: 不会。因为链表插入只改指针指向,不搬移已有节点,也不扩容。

Q4:list 删除元素会导致哪些迭代器失效?

答: 只有被删除节点的迭代器失效,其他节点的迭代器不受影响。

Q5:list 有 reserve 和 capacity 吗?为什么?

答: 没有。list 是非连续空间,每个节点独立申请内存,不需要预留空间,也没有"容量"的概念。

Q6:list 支持 operator[] 随机访问吗?

答: 不支持。底层是链表,访问第 n 个元素需要 O(n) 遍历。只能用迭代器或 range-for。

Q7:list 的 end() 指向哪里?

答: 指向头结点 (哨兵节点),不是最后一个有效元素。front() 返回头结点下一个节点的值,back() 返回头结点上一个节点的值。

Q8:反向迭代器如何实现?

答: 内部包含一个正向迭代器。反向 ++ 调用正向 --,反向 -- 调用正向 ++。operator* 返回前一个位置的值,保证区间对称。

Q9:什么时候用 list,什么时候用 vector?

答:

  • list :大量任意位置插入/删除,不关心随机访问
  • vector :需要随机访问、高效存储、关心缓存效率,插入删除较少
  • 实际中 vector 的使用频率远高于 list(CPU 缓存优势)

Q10:push_back 在 list 和 vector 中的复杂度分别是多少?

答: list 是 O(1) (只改两个指针)。vector 是均摊 O(1)(可能触发扩容,单次最坏 O(n))。

复习建议:重点掌握 list 与 vector 的底层区别、迭代器失效规则差异、以及各自的适用场景。第三、六章是面试高频考点。

生指针 T* | 对节点指针的封装 |

| 随机访问 | O(1) | O(n) |

| 任意位置插入删除 | O(n),需搬移元素 | O(1),只改指针 |


二、核心接口速查

2.1 构造函数

构造函数 说明
list<T> l; 空的 list
list<T> l(n, val); n 个 val
list<T> l(first, last); 迭代器区间构造
list<T> l(const list& x); 拷贝构造

2.2 迭代器

接口 说明
begin() / end() 正向,++ 向后移动
rbegin() / rend() 反向,++ 向前移动(rbegin 即 end 位置,rend 即 begin 位置)

2.3 容量与元素访问

接口 说明
empty() 判空
size() 有效节点个数
front() 第一个元素值的引用
back() 最后一个元素值的引用

2.4 增删改

接口 说明 复杂度
push_front(val) 头插 O(1)
pop_front() 头删 O(1)
push_back(val) 尾插 O(1)
pop_back() 尾删 O(1)
insert(pos, val) 在 pos 前插入 O(1)
erase(pos) 删除 pos 位置节点 O(1)
swap(l1, l2) 交换两个 list O(1)
clear() 清空所有有效元素 O(n)

注意:find 不是 list 的成员函数,是 <algorithm> 中的算法。


三、list 迭代器失效(重点!与 vector 不同)

3.1 核心规则

操作 迭代器是否失效
插入(insert) 不会失效(链表不搬移节点,只改指针)
删除(erase) 只有被删除节点的迭代器失效,其他迭代器不受影响
resize / reserve list 没有这两个接口(非连续空间,无 capacity 概念)

3.2 删除时的安全写法

错误写法:

cpp 复制代码
auto it = l.begin();
while (it != l.end()) {
    l.erase(it);   // it 指向的节点被删除,it 失效
    ++it;           // 失效的 it 再 ++ 崩溃
}

正确写法一(后置 ++):

cpp 复制代码
auto it = l.begin();
while (it != l.end()) {
    l.erase(it++);  // it++ 先返回旧值,再指向下一个,erase 删除旧值
}

正确写法二(用返回值):

cpp 复制代码
auto it = l.begin();
while (it != l.end()) {
    it = l.erase(it);  // C++11 起 erase 返回下一个有效迭代器
}

3.3 list vs vector 迭代器失效对比(面试高频)

场景 vector list
插入元素 可能全部失效(扩容导致空间重分配) 永不失效
删除元素 当前及之后全部失效(元素前移) 仅被删节点失效
失效原因 底层连续空间被释放或元素搬移 节点被删除,指针变野指针

四、反向迭代器实现原理

4.1 核心思想

反向迭代器内部包含一个正向迭代器,通过对正向迭代器进行包装实现:

  • 反向迭代器的 ++ = 正向迭代器的 --
  • 反向迭代器的 -- = 正向迭代器的 ++

4.2 解引用的对称设计

cpp 复制代码
// operator*:返回的是 _it 前一个位置的值
Ref operator*() {
    Iterator temp(_it);
    --temp;
    return *temp;
}

原因 :rbegin() 内部存的是正向 end(),需要 -- 后才指向最后一个有效元素。这是为了保证开始位置和结束位置对称 ,使得 [rbegin(), rend()) 的区间完整覆盖所有元素。

4.3 typename 关键字的作用

cpp 复制代码
typedef typename Iterator::Ref Ref;

告诉编译器 :Iterator::Ref 是一个类型而不是静态成员变量,否则编译器无法区分。


五、list 模拟实现要点

  1. 带头结点的双向循环链表 :头结点不存数据,end() 指向头结点
  2. 节点结构 :包含 _prev、_next 指针和 _data
  3. insert:在指定位置前插入新节点,只改 4 个指针
  4. erase:删除指定节点,只改 2 个指针,返回下一节点
  5. 迭代器类 :需重载 operator*、operator->、operator++、operator--、operator==、operator!=

相关推荐
狗凯之家源码网11 分钟前
PHP 用户反馈系统源码深度评测与实战指南
开发语言·php·用户反馈系统
小溪学编程18 分钟前
从 C++ 的规范变迁看语言发展
jvm·c++·面试
白帽攻防录19 分钟前
SRC 挖洞:WSO2 JWT 算法混淆绕过深度复盘,CVE-2026-5430 不支持的算法怎么变成管理员
网络·算法·安全·网络安全·jwt
谢亮_vipxieliang1 小时前
Stream API 不是银弹:常见坑与性能建议
java·开发语言
无敌贵点大王1 小时前
RTThread学习记录13——关于要使用一个外设,RTThread与cubemx到底要怎么配合?
c语言·stm32·学习·rtthread
小O的算法实验室1 小时前
IEEE TEVC,基于精确与DQN群智能调度方法用于多目标异构USV
算法
迅猛龙办公室1 小时前
实现第一个python程序(HelloWorld)
开发语言·python
phltxy1 小时前
C 语言动态内存管理:从申请空间到安全释放
c语言·开发语言·ui
可乐鸡翅yeah_1 小时前
M3U8 防盗链 URL‑Token 签名,新手开发实操避坑
开发语言·javascript·ios·音视频·safari
ShineWinsu1 小时前
对于Redis:string类型的解析
java·c++·redis·分布式·缓存·面试·string