目录
[一、Vector 是什么?](#一、Vector 是什么?)
[二、Vector 的基本使用](#二、Vector 的基本使用)
[2.1 构造与初始化](#2.1 构造与初始化)
[2.2 迭代器使用](#2.2 迭代器使用)
[2.3 容量操作](#2.3 容量操作)
[三、Vector 的增删查改](#三、Vector 的增删查改)
[3.1 基本操作](#3.1 基本操作)
[4.1 导致迭代器失效的操作](#4.1 导致迭代器失效的操作)
[4.2 错误示例](#4.2 错误示例)
[4.3 正确做法](#4.3 正确做法)
[五、Vector 在算法题中的应用](#五、Vector 在算法题中的应用)
[5.1 只出现一次的数字(异或技巧)](#5.1 只出现一次的数字(异或技巧))
[5.2 杨辉三角](#5.2 杨辉三角)
[六、Vector 的模拟实现注意事项](#六、Vector 的模拟实现注意事项)
[6.1 深拷贝问题](#6.1 深拷贝问题)
[6.2 动态二维数组](#6.2 动态二维数组)
一、Vector 是什么?
vector 是 C++ 标准模板库(STL)中的一个动态数组容器,它能够根据需要自动调整大小,支持快速随机访问,是 C++ 中最常用的容器之一。
二、Vector 的基本使用
2.1 构造与初始化
cpp
#include <vector>
using namespace std;
vector<int> v1; // 空vector
vector<int> v2(5, 10); // 5个元素,每个都是10
vector<int> v3(v2); // 拷贝构造
vector<int> v4(v3.begin(), v3.end()); // 迭代器范围构造
2.2 迭代器使用
cpp
vector<int> v = {1, 2, 3, 4, 5};
// 正向迭代
for (auto it = v.begin(); it != v.end(); ++it) {
cout << *it << " ";
}
// 反向迭代
for (auto it = v.rbegin(); it != v.rend(); ++it) {
cout << *it << " ";
}
2.3 容量操作
cpp
vector<int> v;
cout << v.size(); // 元素个数
cout << v.capacity(); // 当前容量
cout << v.empty(); // 是否为空
v.reserve(100); // 预留至少100个元素的空间
v.resize(50); // 调整大小为50,多出的用默认值填充
注意 :不同编译器下 vector 的扩容策略不同:
-
VS 下按 1.5 倍增长
-
g++ 下按 2 倍增长
三、Vector 的增删查改
3.1 基本操作
cpp
vector<int> v;
// 增
v.push_back(10); // 尾插
v.insert(v.begin(), 5); // 在指定位置插入
// 删
v.pop_back(); // 尾删
v.erase(v.begin()); // 删除指定位置
v.clear(); // 清空
// 查
auto it = find(v.begin(), v.end(), 10); // 查找元素
if (it != v.end()) {
cout << "找到了";
}
// 改
v[0] = 100; // 像数组一样访问
四、迭代器失效问题(重点!)
迭代器失效是使用 vector 时最容易出错的问题之一。简单说,就是当 vector 发生某些操作后,之前获取的迭代器指向的内存可能已经无效。
4.1 导致迭代器失效的操作
-
扩容操作 :
push_back、resize、reserve、insert等可能导致扩容 -
删除操作 :
erase删除元素 -
赋值操作 :
assign
4.2 错误示例
cpp
vector<int> v = {1, 2, 3, 4};
auto it = v.begin();
v.push_back(5); // 可能导致扩容,it失效!
// 错误!it可能指向已释放的内存
while (it != v.end()) {
cout << *it << " ";
++it;
}
4.3 正确做法
cpp
// 删除所有偶数 - 正确写法
vector<int> v = {1, 2, 3, 4, 5};
auto it = v.begin();
while (it != v.end()) {
if (*it % 2 == 0) {
it = v.erase(it); // erase返回下一个有效迭代器
} else {
++it;
}
}
五、Vector 在算法题中的应用
5.1 只出现一次的数字(异或技巧)
cpp
int singleNumber(vector<int>& nums) {
int value = 0;
for (auto e : nums) {
value ^= e; // 利用 a^a=0 的特性
}
return value;
}
5.2 杨辉三角
cpp
vector<vector<int>> generate(int numRows) {
vector<vector<int>> vv(numRows);
for (int i = 0; i < numRows; ++i) {
vv[i].resize(i + 1, 1); // 每行初始化为1
for (int j = 1; j < i; ++j) {
vv[i][j] = vv[i-1][j] + vv[i-1][j-1];
}
}
return vv;
}
六、Vector 的模拟实现注意事项
6.1 深拷贝问题
在模拟实现 vector 时,reserve 中不能使用 memcpy 来拷贝元素,尤其是元素类型涉及资源管理(如 string)时:
cpp
// 错误!浅拷贝会导致问题
void reserve(size_t n) {
// ...
memcpy(_newStart, _start, sizeof(T) * size()); // 危险!
}
// 正确做法:使用循环赋值,调用元素的拷贝构造
for (size_t i = 0; i < size(); ++i) {
_newStart[i] = _start[i]; // 调用T的operator=或拷贝构造
}
6.2 动态二维数组
cpp
// 创建n行的二维数组
vector<vector<int>> vv(n);
// 每行设置不同大小
for (int i = 0; i < n; ++i) {
vv[i].resize(i + 1, 1);
}
七、实战练习建议
-
基础操作 :熟练掌握
push_back、pop_back、operator[]、size等常用接口 -
迭代器理解:理解迭代器失效的原因及解决方案
-
OJ练习:
-
删除排序数组中的重复项
-
只出现一次的数字 II/III
-
数组中出现次数超过一半的数字
-
电话号码字母组合
-
八、总结
vector 是 C++ 中最实用、最高效的容器之一,掌握它需要:
-
理解其底层是动态数组
-
熟悉常用接口的使用场景
-
特别注意迭代器失效问题
-
了解不同编译器下的扩容策略差异
通过理论学习和实际编码练习相结合,你一定能熟练掌握 vector,为后续的 C++ 学习和开发打下坚实基础!