C++ vector /list/map 完整对比与用法

一、底层数据结构

  1. vector(动态数组) 底层:连续内存数组,一块完整堆内存,自动扩容。
  2. list(双向链表) 底层:双向不连续链表,每个节点存数据 + 前后指针,内存分散。
  3. map(有序红黑树) 底层:红黑平衡二叉树,按键 key 自动升序排序,键唯一不可重复。

二、核心性能对比(时间复杂度)

表格

操作 vector list map
随机访问 []/at() O (1) 极快 不支持随机访问 不支持随机访问
头部插入 / 删除 O (n)(整体移位) O (1) 极快 O(log n)
尾部插入 / 删除 均摊 O (1) 极快 O(1) O(log n)
中间插入 / 删除 O (n)(大量移位) O(1) O(log n)
按值查找 O (n) 遍历 O (n) 遍历 按键查找 O (log n)
内存开销 小,仅存数据 大,额外存双向指针 大,树平衡额外标记

三、基础代码示例

1. vector 动态数组(优先日常容器)

适用:频繁随机读写、尾部增删,很少中间插入

cpp 复制代码
#include <vector>
#include <iostream>
using namespace std;

int main() {
    vector<int> vec;
    vec.push_back(10);  // 尾部添加
    vec.push_back(20);
    vec.insert(vec.begin(), 5); // 头部插入,效率低
    cout << vec[1]; // 随机访问 O(1)

    // 遍历
    for (int x : vec) cout << x;
    return 0;
}

2. list 双向链表

适用:频繁头部 / 中间增删,几乎不随机读取

cpp 复制代码
#include <list>
int main() {
    list<int> lst;
    lst.push_back(1);
    lst.push_front(0); // 头部插入很快
    // 无 lst[0] 这种随机访问,只能迭代器遍历
    for (auto it = lst.begin(); it != lst.end(); ++it) {}
    return 0;
}

3. map 有序键值对

适用:需要key 自动排序、按键快速查找、键不重复

cpp 复制代码
#include <map>
int main() {
    map<string, int> mp;
    mp["张三"] = 18;
    mp["李四"] = 20;
    // 自动按字符串升序排列,按键查询O(logn)
    cout << mp["张三"];
    return 0;
}

四、优缺点总结

vector

✅ 优点:随机访问超快、缓存友好、内存紧凑、遍历速度最快 ❌ 缺点:头部 / 中间插入删除大量元素移位,扩容会拷贝数据 场景:数组、缓存、数据批量存储、绝大多数业务首选

list

✅ 优点:任意位置插入删除仅修改指针,无内存拷贝 ❌ 缺点:不支持随机访问,遍历慢、内存碎片多、缓存不命中 场景:频繁中间增删、队列节点管理、极少查询下标

map

✅ 优点:key 有序,按键二分查找,插入删除稳定 logn 复杂度 ❌ 缺点:不能下标随机遍历 value,树结构内存开销大 场景:字典、有序映射、需要按 key 快速检索的配对数据

五、选型快速口诀

  1. 要下标随机取数据 → vector
  2. 频繁在中间 / 头部删改,不用下标 → list
  3. 存 key-value、需要自动排序、按键查找 → map