一、底层数据结构
- vector(动态数组) 底层:连续内存数组,一块完整堆内存,自动扩容。
- list(双向链表) 底层:双向不连续链表,每个节点存数据 + 前后指针,内存分散。
- 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 快速检索的配对数据
五、选型快速口诀
- 要下标随机取数据 → vector
- 频繁在中间 / 头部删改,不用下标 → list
- 存 key-value、需要自动排序、按键查找 → map