vector完胜:其连续内存使operator[]为O(1),而list链表结构致随机访问为O(n);误用std::next遍历list会显著降速,缓存索引等场景必选vector。

随机访问:vector完胜,list根本不能比
如果你需要按索引快速取元素,vector 是唯一合理选择。它的底层是连续内存,operator[] 是 O(1) 时间;而 list 是双向链表,要访问第 n 个元素必须从头或尾逐个跳指针,实际就是 O(n) ——哪怕只是读 lst.begin() 往后挪 1000 次,也比 v[1000] 慢一个数量级。
常见错误现象:std::next(lst.begin(), i) 在循环里反复调用,误以为和数组下标一样轻量;其实每次都在做链表遍历。
- 场景:实现缓存索引、坐标映射、批量读取中间数据 → 必用
vector - 注意:
list的size()在 C++11 后是 O(1),但advance()或std::next()仍是 O(n) - 性能影响:10 万元素时,随机读第 5 万项,
vector耗时通常 list 常超 1μs(相差百倍)
中间插入/删除:list有优势,但仅限已知迭代器位置
list 的插入删除确实是 O(1),但前提是——你已经持有那个位置的 iterator。如果为了插入先用 std::find 找位置,那整体还是 O(n);而 vector 在尾部插入(push_back)也是均摊 O(1),且现代 CPU 缓存友好,实际可能更快。
典型误用:for (auto it = lst.begin(); it != lst.end(); ++it) if (*it == x) { lst.insert(it, y); break; } —— 看似“list 插入快”,实则查找 + 插入两步都慢,且破坏了局部性。
- 真正适合
list的场景:维护一个动态排序队列,每次在已知节点(如回调传入的iterator)前后增删 -
vector中间插入代价高:涉及内存搬移,insert(v.begin() + pos, val)是 O(n - pos) - 兼容性提醒:C++11 后
list迭代器不因其他元素增删失效,vector迭代器在push_back可能扩容时全部失效
内存与缓存:vector紧凑,list开销大且不友好
每个 list 节点除了存你的数据,还要额外两个指针(prev/next),64 位系统就是 16 字节固定开销;而 vector 就是纯数据排列。更关键的是,list 节点分散在堆上,一次遍历触发大量 cache miss;vector 顺序访问时 CPU 预取几乎满效率。
错误认知:“list 内存占用小”——错。存 1000 个 int,vector 占 4KB,list 至少 1000×(4+16)=20KB(还不算 malloc 元数据)。
- 参数差异:
vector可通过reserve()预分配减少 realloc;list无法预估节点分布,splice()是唯一零拷贝移动操作 - 性能影响:遍历 10 万元素,
vector常在 100μs 内完成,list很容易破 1ms,尤其在 L3 cache 不足时差距更大 - 调试提示:用
valgrind --tool=massif对比两者内存 footprint,list的“碎片峰值”常被低估
什么时候真该选 list?别靠直觉,看这三点
现实中绝大多数所谓“频繁插入删除”的需求,用 vector + 标记删除(或 std::remove_if)、或换用 deque 更合适。list 的适用面极窄,只在同时满足以下条件时才值得考虑:
- 插入/删除位置已由外部逻辑精确提供(例如事件驱动中回调传入的
iterator),无需查找 - 容器生命周期长、大小波动剧烈,且不允许任何迭代器/引用失效(
vector扩容、erase都会破坏) - 数据本身很大(如
std::array),且移动构造开销远高于指针操作 —— 此时list的节点指针交换才有意义
最容易被忽略的一点:list 的 sort() 是稳定排序且不依赖 operator(用自定义谓词),但它内部是归并排序、需额外 O(n) 空间;而 vector 的 std::sort 是 introsort,原地、更快、更省内存——别因为“list 自带 sort”就选它。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











