一、vector 的核心概念与底层机制
1.1 动态数组的本质
- 连续内存存储:与普通数组相同,vector 使用连续的内存空间,支持 O (1) 时间复杂度的随机访问。
- 动态扩容特性:通过
push_back
等操作自动调整容量,无需手动管理内存。 - 与数组的区别:
特性 | 普通数组 | vector |
---|
内存分配 | 静态分配 | 动态分配 |
大小可变 | 否 | 是 |
越界检查 | 无 | 无(需手动检查) |
内存管理 | 手动释放 | 自动管理 |
1.2 扩容策略的深度解析
二、vector 的基础用法与高级操作
2.1 初始化方式的全面总结
方式 | 示例代码 | 说明 |
---|
空容器 | vector<int> v1; | 初始容量为 0 |
指定大小与初始值 | vector<int> v2(10, 2); | 10 个元素,值为 2 |
拷贝构造 | vector<int> v3(v2); | 复制 v2 的内容 |
迭代器范围构造 | vector<int> v4(v2.begin(), v2.end()); | 复制区间 [begin, end) 的元素 |
其他容器转换 | vector<char> v5(s.begin(), s.end()); | 将 string 转换为 vector |
2.2 空间管理函数的对比
函数 | 作用 | 复杂度 | 示例代码 |
---|
size() | 返回有效元素个数 | O(1) | cout << v.size(); |
capacity() | 返回当前分配的最大容量 | O(1) | cout << v.capacity(); |
reserve(n) | 预留至少 n 个元素的空间 | O(n) | v.reserve(100); |
resize(n) | 调整元素个数为 n,新元素默认值为 0 | O(n) | v.resize(5); |
empty() | 判断容器是否为空 | O(1) | if (v.empty()) ... |
2.3 迭代器的高级应用
三、增删查改操作的最佳实践
3.1 插入操作的性能优化
- 尾插:
push_back()
时间复杂度为 O (1)(均摊)。 - 任意位置插入:
insert(pos, val)
时间复杂度为 O (n)(需移动元素)。 - 批量插入:
// 插入多个相同元素
v.insert(v.begin(), 5, -1); // 在开头插入5个-1// 插入其他容器元素
vector<int> src = {1, 2, 3};
v.insert(v.end(), src.begin(), src.end());
3.2 删除操作的注意事项
3.3 元素访问的安全方式
四、迭代器失效问题与解决方案
4.1 失效场景分析
操作类型 | 迭代器失效原因 | 影响范围 |
---|
插入元素 | 可能导致扩容,所有迭代器失效 | 全部迭代器 |
删除元素 | 被删除元素之后的迭代器失效 | 删除点之后的迭代器 |
resize() | 若容量变化,所有迭代器失效 | 全部迭代器(若容量变化) |
4.2 经典案例与修复方案
案例 1:插入后删除导致的失效
// 错误代码
auto pos = find(v.begin(), v.end(), 2);
v.insert(pos, 10); // 插入后pos失效
v.erase(pos); // 非法访问// 正确代码
auto pos = find(v.begin(), v.end(), 2);
v.insert(pos, 10);
pos = find(v.begin(), v.end(), 2); // 重新获取pos
v.erase(pos);
案例 2:遍历删除偶数时的越界
// 错误代码
for (auto it = v.begin(); it != v.end(); ++it) {if (*it % 2 == 0) {v.erase(it); // it失效后继续递增}
}// 正确代码
for (auto it = v.begin(); it != v.end(); ) {if (*it % 2 == 0) {it = v.erase(it); // erase返回下一个有效迭代器} else {++it;}
}
五、vector 的性能优化与最佳实践
5.1 预分配空间
5.2 避免不必要的拷贝
5.3 与其他容器的选择对比
容器 | 随机访问 | 插入 / 删除(非尾部) | 内存占用 | 适用场景 |
---|
vector | O(1) | O(n) | 较小 | 动态数组、频繁随机访问 |
list | O(n) | O(1) | 较大 | 频繁插入 / 删除 |
deque | O(1) | O (1)(首尾) | 中等 | 双端队列操作 |
六、常见问题与解答
6.1 为什么 vector 的 capacity 总是大于等于 size?
- 原因:vector 会预分配额外空间以优化插入操作的性能。
6.2 如何释放 vector 的多余内存?
6.3 vector<bool>的特殊性
- 注意:
vector<bool>
并非存储bool
类型,而是特化为bitset
以节省空间,迭代器行为可能不同。
七、扩展资源与推荐阅读
- C++ 官方文档:vector
- 《C++ Primer》:第 9 章 顺序容器
- Stack Overflow 专题:vector 扩容策略