一、list 是什么
list 是双向循环链表
- 底层不是连续内存,每个节点独立分配
- 每个节点存:数据 + 前驱指针 + 后继指针
- 不支持下标随机访问
[] - 任意位置插入、删除效率极高,不会移动大量元素
头文件:
#include <list>
using namespace std;
二、list 常用初始化
// 1. 空链表
list<int> l1;
// 2. 5个元素,默认0
list<int> l2(5);
// 3. 5个元素,全初始化为6
list<int> l3(5, 6);
// 4. 列表初始化
list<int> l4 = {10,20,30,40};
三、list 核心增删接口
1. 头尾插入删除
list<int> l;
l.push_back(10); // 尾插
l.push_front(20); // 头插
l.pop_back(); // 尾删
l.pop_front(); // 头删
2. 任意位置插入 insert
// 在迭代器位置前插入元素
l.insert(l.begin(), 88);
3. 删除 erase
// 删除迭代器指向元素
l.erase(l.begin());
// 清空所有
l.clear();
4. 常用属性接口
l.size(); // 元素个数
l.empty(); // 是否为空
l.front(); // 头部元素
l.back(); // 尾部元素
四、list 遍历方式
重点:list 不支持下标 [] 访问 只能用:迭代器、范围 for
1. 迭代器遍历
list<int> l = {1,2,3,4,5};
for(list<int>::iterator it = l.begin(); it != l.end(); ++it)
{
cout << *it << " ";
}
2. 范围 for 遍历(最简)
for(int val : l)
{
cout << val << " ";
}
五、list 独有常用操作
// 反转链表
l.reverse();
// 排序
l.sort();
// 去重(相邻重复才去重,建议先sort再unique)
l.unique();
// 删除指定值的所有元素
l.remove(3);
六、完整实战示例代码
#include <iostream>
#include <list>
using namespace std;
int main()
{
list<int> l;
// 头尾插入
l.push_back(1);
l.push_back(3);
l.push_front(10);
l.push_front(20);
cout << "原始链表:";
for(int val : l)
{
cout << val << " ";
}
cout << endl;
// 排序 + 反转
l.sort();
cout << "排序后:";
for(int val : l) cout << val << " ";
cout << endl;
l.reverse();
cout << "反转后:";
for(int val : l) cout << val << " ";
return 0;
}
七、vector /deque/list 终极对比(必背)
表格
| 容器 | 底层 | 随机访问 [] | 头尾增删 | 中间增删 | 适用场景 |
|---|---|---|---|---|---|
| vector | 连续数组 | 支持 | 尾快头慢 | 慢 | 纯尾部操作、频繁随机访问 |
| deque | 分段块 | 支持 | 头尾都快 | 慢 | 频繁头尾插入删除 |
| list | 双向链表 | 不支持 | 头尾极快 | 极快 | 频繁任意位置插入删除、不常查 |
选型口诀:
- 要随机访问、只在尾部操作 → vector
- 要频繁头尾增删 → deque
- 频繁中间插入删除、不在乎下标访问 → list
八、新手高频易错点
- 给 list 用下标
l[0]编译报错 - 忘记 list 不支持随机访问,迭代器只能
++--,不能it + 2 - unique 不去重,没先排序
- 混淆三者适用场景,乱用容器导致效率低
- list 迭代器增删后不会失效(和 vector 不一样)
九、今日重点总结
- list 底层是双向循环链表,非连续内存
- 不支持下标
[],只能迭代器 / 范围 for 遍历 - 任意位置插入删除效率高,自带 sort、reverse、unique、remove
- 中间频繁增删优先选 list
- 掌握三大线性容器:vector、deque、list 选型完全够用