std::list 是双向链表,任意位置插入删除为 o(1),不支持随机访问;适用于频繁中间增删且无需下标访问的场景,如任务队列;误用包括用下标遍历或替代 vector 进行随机访问。

直接说结论: C++ 的 std::list 是双向链表,插入和删除(任意位置)都是 O(1) 时间复杂度,但不支持随机访问——别用 operator[] 或 at(),否则编译报错或运行崩溃。
为什么用 list 而不是 vector?
当你频繁在中间增删元素,且不关心下标访问时,list 才有意义。比如实现一个任务队列,经常在头部插入新任务、在尾部移除已完成任务,或根据条件从中间摘除某节点——这时 vector 每次删中间都要移动后续所有元素,而 list 只需改几个指针。
常见误用场景:
- 用 list 存数据后反复写 for (int i = 0; i → 编译失败,<code>list 没有 operator[]
- 插入后立刻用 begin() + n 找第 n 个元素 → 不合法,list 迭代器不支持算术运算(+、-)
push_front / push_back 和 insert 的区别
push_front 和 push_back 是常量时间的头/尾插入;insert 必须传一个有效迭代器作为位置锚点,它在该迭代器「之前」插入新元素。
-
lst.push_front(x):等价于lst.insert(lst.begin(), x) -
lst.insert(it, x)中的it必须是本容器的合法迭代器(不能是end()以外的失效迭代器) - 想在第 n 个位置插入?得先用
std::next(lst.begin(), n)走 n 步(O(n) 时间),再insert—— 这就是“不支持随机访问”的代价 - 批量插入推荐用
insert(it, first, last)(如另一个容器的区间),比循环调用快
erase 删除时最容易踩的坑
erase 接收迭代器(或迭代器对),返回**下一个有效迭代器**——这是关键,也是最常出错的地方。
立即学习“C++免费学习笔记(深入)”;
错误写法:for (auto it = lst.begin(); it != lst.end(); ++it) { if (*it == target) lst.erase(it); }
问题:erase 后 it 失效,再执行 ++it 是未定义行为(多半崩溃)
正确写法(推荐):for (auto it = lst.begin(); it != lst.end(); ) { if (*it == target) it = lst.erase(it); else ++it; }
或者更简洁:lst.remove_if([](int x) { return x == target; });(注意:这是值删除,不是按迭代器删)
其他注意点:
- lst.erase(lst.begin()) 安全;但 lst.erase(--lst.end()) 要小心,空容器时 --end() 无效
- clear() 后所有迭代器立即失效,不能再用
- pop_front()/pop_back() 只删头/尾,不返回迭代器,也不接受参数
真正难的不是语法,是记住:每次 erase 都要处理返回值,每次遍历删除都要避免迭代器失效。链表操作本身很快,但逻辑写错一丁点,结果就不可预测。











