一、Vector 的核心概念与特性
Vector 是 C++ 标准库中最常用的动态数组容器,其底层基于连续内存存储元素,兼具数组的高效访问与动态扩容的灵活性。以下是其核心特性:
1.1 核心特性对比
特性 | 普通数组 | Vector 容器 |
---|---|---|
内存分配 | 静态固定 | 动态增长 |
访问效率 | O(1) | O(1) |
插入 / 删除效率 | 需手动管理 | 尾部操作 O (1),其他 O (n) |
迭代器支持 | 指针访问 | 双向迭代器 |
内存管理 | 手动释放 | 自动内存管理 |
1.2 空间增长策略
Vector 采用指数增长策略(通常为 1.5 倍或 2 倍),以平衡频繁扩容带来的性能损耗。这种策略保证了均摊时间复杂度为 O (1) 的尾插操作。
扩容机制示意图:
初始容量: 1 → 插入元素 → 容量不足 → 扩容至2 → 继续插入 → 容量不足 → 扩容至4 → ...
二、Vector 的基础操作与使用技巧
2.1 构造函数全解析
2.1.1 基本构造方式
// 空构造
vector<int> v1;// 填充构造
vector<double> v2(10, 3.14); // 10个3.14// 范围构造
vector<char> v3("Hello", "Hello" + 5);// 拷贝构造
vector<string> v4(v3.begin(), v3.end());
2.1.2 C++11 新增构造方式
// 初始化列表构造
vector<int> v5 = {1, 2, 3, 4, 5};// 移动构造
vector<int> v6 = move(v5); // 转移资源所有权
2.2 空间管理函数
2.2.1 容量相关函数
vector<int> v = {1, 2, 3};
cout << v.size() << endl; // 3
cout << v.capacity() << endl; // 3(未扩容时size等于capacity)
cout << v.max_size() << endl; // 最大理论容量
2.2.2 内存优化技巧
vector<int>().swap(v); // 收缩内存(shrink-to-fit)
v.reserve(100); // 预分配内存
2.3 元素访问与遍历
2.3.1 随机访问
vector<int> v = {10, 20, 30};
cout << v[1] << endl; // 20(直接访问)
cout << v.at(1) << endl; // 20(带边界检查)
2.3.2 迭代器遍历
// 正向迭代
for (auto it = v.begin(); it != v.end(); ++it) {cout << *it << " ";
}// 反向迭代
for (auto rit = v.rbegin(); rit != v.rend(); ++rit) {cout << *rit << " ";
}
2.3.3 范围 for 遍历
for (const auto& element : v) {cout << element << " ";
}
三、增删查改操作深度解析
3.1 插入操作对比
操作 | 时间复杂度 | 适用场景 |
---|---|---|
push_back | O(1) | 尾部快速插入 |
insert | O(n) | 任意位置插入 |
emplace_back | O(1) | 原地构造对象 |
示例:emplace_back 的优势
class MyClass {
public:MyClass(int val) : value(val) {cout << "Constructing MyClass" << endl;}
private:int value;
};vector<MyClass> v;
v.emplace_back(42); // 直接构造,无需拷贝
3.2 删除操作详解
vector<int> v = {1, 2, 3, 4, 5};// 删除指定元素
v.erase(find(v.begin(), v.end(), 3));// 删除区间
v.erase(v.begin() + 1, v.begin() + 3);// 清空容器
v.clear();
3.3 查找与修改
// 查找元素
auto pos = find(v.begin(), v.end(), 20);
if (pos != v.end()) {*pos = 200; // 修改元素值
}// 替换元素
replace(v.begin(), v.end(), 10, 100); // 将所有10替换为100
四、迭代器失效场景与解决方案
4.1 失效场景分析
操作类型 | 迭代器失效情况 |
---|---|
尾插(push_back) | 可能失效(若发生扩容) |
插入(insert) | 失效(包括当前迭代器及之后的) |
删除(erase) | 失效(当前迭代器及之后的) |
扩容(reserve) | 失效(所有迭代器) |
4.2 典型错误与修复
错误示例:
vector<int> v = {1, 2, 3, 4};
auto it = v.begin();
while (it != v.end()) {if (*it % 2 == 0) {v.erase(it); // 错误:迭代器失效}++it;
}
正确实现:
auto it = v.begin();
while (it != v.end()) {if (*it % 2 == 0) {it = v.erase(it); // 接收新迭代器} else {++it;}
}
五、性能优化与内存管理
5.1 预分配内存
vector<int> v;
v.reserve(1000); // 预分配1000个元素的空间
for (int i = 0; i < 1000; ++i) {v.push_back(i); // 避免多次扩容
}
5.2 内存收缩
vector<int>().swap(v); // 收缩内存到实际元素大小
5.3 避免不必要的拷贝
// 错误:产生临时对象
vector<int> v = {1, 2, 3};
vector<int> v2 = v; // 拷贝构造// 正确:使用移动语义
vector<int> v2 = move(v); // 转移资源
六、常见面试问题与解答
6.1 Vector与List的区别
特性 | Vector | List |
---|---|---|
内存布局 | 连续内存 | 非连续内存 |
访问效率 | 高(随机访问) | 低(只能顺序访问) |
插入 / 删除 | 尾部高效,其他位置低 | 任意位置高效 |
迭代器类型 | 随机访问迭代器 | 双向迭代器 |
6.2 如何实现 Vector 的深拷贝
template<typename T>
class MyVector {
private:T* data;size_t size;size_t capacity;public:MyVector(const MyVector& other) : size(other.size), capacity(other.capacity) {data = new T[capacity];copy(other.data, other.data + size, data);}
};
七、C++11 新特性增强
7.1 emplace 系列函数
v.emplace(v.begin() + 2, 42); // 在位置2插入42
v.emplace_back(100); // 尾插100
7.2 初始化列表构造
vector<int> v = {1, 2, 3, 4}; // 使用初始化列表
7.3 移动语义支持
vector<int> v1 = {1, 2, 3};
vector<int> v2 = move(v1); // 高效转移资源
八、实战案例分析
8.1 性能优化案例
问题: 在频繁插入元素时,Vector 性能下降明显。
解决方案:
vector<int> v;
v.reserve(1000); // 预分配内存
for (int i = 0; i < 1000; ++i) {v.emplace_back(i); // 原地构造
}
8.2 迭代器失效案例
问题: 在循环中删除元素导致程序崩溃。
解决方案:
auto it = v.begin();
while (it != v.end()) {if (*it % 2 == 0) {it = v.erase(it); // 更新迭代器} else {++it;}
}
九、参考资源
- C++ Vector 官方文档
- STL 源码剖析
- C++11 新特性详解