C++ vector 使用详解
vector 是 C++ 标准模板库(STL)中最常用的动态数组容器,它提供了动态大小、自动内存管理和丰富的操作函数。
1. 基本概念和特点
特性:
- 动态数组:可以动态调整大小
- 连续内存:元素在内存中连续存储
- 自动内存管理:自动分配和释放内存
- 随机访问:支持通过索引快速访问
- 类型安全:模板类型确保类型安全
头文件
#include <vector>
#include <iostream> // 用于输出
2. vector 的创建和初始化
#include <vector>
#include <iostream>
#include <algorithm> // 用于std::copy
using namespace std;
int main() {
// 1. 空vector
vector<int> vec1;
// 2. 指定初始大小,默认值初始化
vector<int> vec2(5); // 5个元素,默认值为0
vector<string> vec3(3); // 3个字符串,默认值为空字符串
// 3. 指定初始大小和初始值
vector<int> vec4(5, 100); // 5个元素,每个都是100
vector<string> vec5(3, "Hello"); // 3个字符串,每个都是"Hello"
// 4. 使用初始化列表(C++11)
vector<int> vec6 = {1, 2, 3, 4, 5};
vector<int> vec7{10, 20, 30, 40, 50};
// 5. 从数组初始化
int arr[] = {1, 2, 3, 4, 5};
vector<int> vec8(arr, arr + sizeof(arr)/sizeof(arr[0]));
// 6. 从另一个vector初始化(拷贝)
vector<int> vec9(vec6); // 拷贝构造
vector<int> vec10 = vec7; // 拷贝赋值
// 7. 使用迭代器范围
vector<int> vec11(vec6.begin(), vec6.begin() + 3); // 包含前3个元素
return 0;
}
3. 基本操作
访问元素
vector<int> vec = {10, 20, 30, 40, 50};
// 1. 使用下标运算符[](不检查边界)
cout << vec[0] << endl; // 10
cout << vec[2] << endl; // 30
vec[1] = 25; // 修改元素
// 2. 使用at()方法(检查边界,越界抛出异常)
cout << vec.at(0) << endl; // 10
// cout << vec.at(10) << endl; // 抛出std::out_of_range异常
// 3. 访问首尾元素
cout << vec.front() << endl; // 第一个元素: 10
cout << vec.back() << endl; // 最后一个元素: 50
// 4. 使用data()获取底层数组指针
int* ptr = vec.data();
cout << *ptr << endl; // 第一个元素: 10
获取大小和容量
vector<int> vec = {1, 2, 3, 4, 5};
// 当前元素数量
cout << "大小(size): " << vec.size() << endl;
// 最大可容纳元素数量(无需重新分配内存)
cout << "容量(capacity): " << vec.capacity() << endl;
// 可容纳的最大元素数量(理论值)
cout << "最大大小(max_size): " << vec.max_size() << endl;
// 检查是否为空
if (vec.empty()) {
cout << "vector为空" << endl;
} else {
cout << "vector不为空" << endl;
}
4. 添加和删除元素
添加元素
vector<int> vec = {1, 2, 3};
// 1. push_back() - 在末尾添加元素
vec.push_back(4); // vec: {1, 2, 3, 4}
vec.push_back(5); // vec: {1, 2, 3, 4, 5}
// 2. insert() - 在指定位置插入元素
vector<int>::iterator it = vec.begin() + 2;
vec.insert(it, 99); // 在位置2插入99
// vec: {1, 2, 99, 3, 4, 5}
// 3. insert() - 插入多个相同元素
vec.insert(vec.begin() + 1, 3, 88); // 在位置1插入3个88
// vec: {1, 88, 88, 88, 2, 99, 3, 4, 5}
// 4. insert() - 插入另一个容器的元素
vector<int> another = {100, 200, 300};
vec.insert(vec.end(), another.begin(), another.end());
// vec: {1, 88, 88, 88, 2, 99, 3, 4, 5, 100, 200, 300}
// 5. emplace_back() - 在末尾构造元素(效率更高)
vec.emplace_back(500); // 直接构造,避免拷贝
删除元素
vector<int> vec = {1, 2, 3, 4, 5, 6, 7, 8, 9};
// 1. pop_back() - 删除最后一个元素
vec.pop_back(); // 删除9
// vec: {1, 2, 3, 4, 5, 6, 7, 8}
// 2. erase() - 删除指定位置元素
vec.erase(vec.begin() + 2); // 删除位置2的元素(3)
// vec: {1, 2, 4, 5, 6, 7, 8}
// 3. erase() - 删除范围元素
vec.erase(vec.begin() + 1, vec.begin() + 4); // 删除[1, 4)的元素
// vec: {1, 6, 7, 8}
// 4. clear() - 删除所有元素
vec.clear(); // vec变为空
cout << "大小: " << vec.size() << endl; // 0
5. 遍历vector
vector<int> vec = {10, 20, 30, 40, 50};
// 1. 使用下标遍历
cout << "下标遍历: ";
for (size_t i = 0; i < vec.size(); i++) {
cout << vec[i] << " ";
}
cout << endl;
// 2. 使用迭代器遍历
cout << "迭代器遍历: ";
for (vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {
cout << *it << " ";
}
cout << endl;
// 3. 使用const迭代器(只读)
cout << "const迭代器遍历: ";
for (vector<int>::const_iterator it = vec.begin(); it != vec.end(); ++it) {
cout << *it << " ";
}
cout << endl;
// 4. 使用auto关键字简化
cout << "auto遍历: ";
for (auto it = vec.begin(); it != vec.end(); ++it) {
cout << *it << " ";
}
cout << endl;
// 5. 使用反向迭代器
cout << "反向遍历: ";
for (auto it = vec.rbegin(); it != vec.rend(); ++it) {
cout << *it << " ";
}
cout << endl;
// 6. 使用范围for循环(C++11)
cout << "范围for循环: ";
for (int value : vec) {
cout << value << " ";
}
cout << endl;
// 7. 使用范围for循环(引用修改元素)
cout << "修改前: ";
for (int value : vec) {
cout << value << " ";
}
cout << endl;
for (int& value : vec) {
value *= 2; // 每个元素乘以2
}
cout << "修改后: ";
for (int value : vec) {
cout << value << " ";
}
cout << endl;
6. 容量管理
vector<int> vec;
// 查看初始状态
cout << "初始状态 - 大小: " << vec.size()
<< ", 容量: " << vec.capacity() << endl;
// 添加元素观察容量变化
for (int i = 0; i < 10; i++) {
vec.push_back(i);
cout << "添加第" << i+1 << "个元素 - 大小: " << vec.size()
<< ", 容量: " << vec.capacity() << endl;
}
// reserve() - 预留容量(避免频繁重新分配)
vector<int> vec2;
vec2.reserve(100); // 预留100个元素的容量
cout << "reserve后 - 大小: " << vec2.size()
<< ", 容量: " << vec2.capacity() << endl;
// shrink_to_fit() - 减小容量到刚好容纳元素(C++11)
vec.shrink_to_fit();
cout << "shrink_to_fit后 - 大小: " << vec.size()
<< ", 容量: " << vec.capacity() << endl;
// resize() - 改变大小
vector<int> vec3 = {1, 2, 3};
cout << "原始: ";
for (int v : vec3) cout << v << " ";
cout << endl;
vec3.resize(5); // 增大,新元素默认初始化为0
cout << "resize(5): ";
for (int v : vec3) cout << v << " ";
cout << endl;
vec3.resize(3); // 缩小,多余元素被丢弃
cout << "resize(3): ";
for (int v : vec3) cout << v << " ";
cout << endl;
vec3.resize(5, 99); // 增大,新元素初始化为99
cout << "resize(5, 99): ";
for (int v : vec3) cout << v << " ";
cout << endl;
7. 二维vector(vector的vector)
// 创建二维vector(类似矩阵)
vector<vector<int>> matrix;
// 方法1:先创建行,再添加列
matrix.resize(3); // 3行
for (int i = 0; i < 3; i++) {
matrix[i].resize(4); // 每行4列,初始化为0
}
// 方法2:直接初始化
vector<vector<int>> matrix2 = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
// 访问元素
cout << "matrix2[1][2] = " << matrix2[1][2] << endl; // 7
// 遍历二维vector
cout << "二维vector遍历:" << endl;
for (size_t i = 0; i < matrix2.size(); i++) {
for (size_t j = 0; j < matrix2[i].size(); j++) {
cout << matrix2[i][j] << "\t";
}
cout << endl;
}
// 使用范围for循环
cout << "使用范围for循环:" << endl;
for (const auto& row : matrix2) {
for (int val : row) {
cout << val << "\t";
}
cout << endl;
}
// 不规则二维vector(每行长度不同)
vector<vector<int>> jagged = {
{1},
{2, 3},
{4, 5, 6},
{7, 8, 9, 10}
};
cout << "不规则二维vector:" << endl;
for (const auto& row : jagged) {
cout << "行大小: " << row.size() << " | 元素: ";
for (int val : row) {
cout << val << " ";
}
cout << endl;
}
8. 实用操作和算法
#include <vector>
#include <iostream>
#include <algorithm> // STL算法
#include <numeric> // 数值算法
using namespace std;
int main() {
vector<int> vec = {5, 2, 8, 1, 9, 3};
// 1. 排序
sort(vec.begin(), vec.end());
cout << "升序排序: ";
for (int v : vec) cout << v << " ";
cout << endl;
// 降序排序
sort(vec.begin(), vec.end(), greater<int>());
cout << "降序排序: ";
for (int v : vec) cout << v << " ";
cout << endl;
// 2. 查找
auto it = find(vec.begin(), vec.end(), 8);
if (it != vec.end()) {
cout << "找到元素8,位置: " << distance(vec.begin(), it) << endl;
} else {
cout << "未找到元素8" << endl;
}
// 二分查找(需要先排序)
sort(vec.begin(), vec.end()); // 先排序
bool found = binary_search(vec.begin(), vec.end(), 5);
cout << "二分查找5: " << (found ? "找到" : "未找到") << endl;
// 3. 反转
reverse(vec.begin(), vec.end());
cout << "反转后: ";
for (int v : vec) cout << v << " ";
cout << endl;
// 4. 累加
int sum = accumulate(vec.begin(), vec.end(), 0);
cout << "元素总和: " << sum << endl;
// 5. 统计
int count5 = count(vec.begin(), vec.end(), 5);
cout << "元素5出现次数: " << count5 << endl;
// 6. 最大值和最小值
auto maxIt = max_element(vec.begin(), vec.end());
auto minIt = min_element(vec.begin(), vec.end());
cout << "最大值: " << *maxIt << ",最小值: " << *minIt << endl;
// 7. 删除重复元素(需要先排序)
vec = {1, 2, 2, 3, 3, 3, 4, 5, 5};
auto last = unique(vec.begin(), vec.end());
vec.erase(last, vec.end());
cout << "去重后: ";
for (int v : vec) cout << v << " ";
cout << endl;
return 0;
}
9. vector的性能特点
#include <vector>
#include <iostream>
#include <chrono>
using namespace std;
using namespace chrono;
int main() {
// vector在不同操作下的性能
vector<int> vec;
// 1. 尾部插入 - O(1) 平摊时间复杂度
auto start = high_resolution_clock::now();
for (int i = 0; i < 100000; i++) {
vec.push_back(i);
}
auto end = high_resolution_clock::now();
auto duration = duration_cast<milliseconds>(end - start);
cout << "尾部插入100000个元素耗时: " << duration.count() << "ms" << endl;
// 2. 头部插入 - O(n),很慢
vec.clear();
start = high_resolution_clock::now();
for (int i = 0; i < 10000; i++) {
vec.insert(vec.begin(), i); // 每次在头部插入
}
end = high_resolution_clock::now();
duration = duration_cast<milliseconds>(end - start);
cout << "头部插入10000个元素耗时: " << duration.count() << "ms" << endl;
// 3. 随机访问 - O(1)
start = high_resolution_clock::now();
long long sum = 0;
for (size_t i = 0; i < vec.size(); i++) {
sum += vec[i];
}
end = high_resolution_clock::now();
duration = duration_cast<microseconds>(end - start);
cout << "随机访问所有元素求和耗时: " << duration.count() << "μs" << endl;
return 0;
}
10. 实际应用示例
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
// 学生类
class Student {
public:
string name;
int score;
Student(string n, int s) : name(n), score(s) {}
// 用于排序的比较函数
static bool compareByScore(const Student& a, const Student& b) {
return a.score > b.score; // 按分数降序
}
void display() const {
cout << name << ": " << score << "分" << endl;
}
};
int main() {
// 示例1:学生管理系统
vector<Student> students;
// 添加学生
students.push_back(Student("张三", 85));
students.push_back(Student("李四", 92));
students.push_back(Student("王五", 78));
students.emplace_back("赵六", 95); // 直接构造
// 按分数排序
sort(students.begin(), students.end(), Student::compareByScore);
cout << "学生成绩排名:" << endl;
for (const auto& student : students) {
student.display();
}
// 示例2:动态矩阵运算
vector<vector<double>> matrixA = {
{1.0, 2.0, 3.0},
{4.0, 5.0, 6.0}
};
vector<vector<double>> matrixB = {
{7.0, 8.0},
{9.0, 10.0},
{11.0, 12.0}
};
// 矩阵乘法
int rowsA = matrixA.size();
int colsA = matrixA[0].size();
int colsB = matrixB[0].size();
vector<vector<double>> result(rowsA, vector<double>(colsB, 0.0));
for (int i = 0; i < rowsA; i++) {
for (int j = 0; j < colsB; j++) {
for (int k = 0; k < colsA; k++) {
result[i][j] += matrixA[i][k] * matrixB[k][j];
}
}
}
cout << "\n矩阵乘法结果:" << endl;
for (const auto& row : result) {
for (double val : row) {
cout << val << "\t";
}
cout << endl;
}
// 示例3:过滤和转换
vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// 过滤出偶数
vector<int> evenNumbers;
copy_if(numbers.begin(), numbers.end(), back_inserter(evenNumbers),
[](int n) { return n % 2 == 0; });
cout << "\n偶数: ";
for (int n : evenNumbers) cout << n << " ";
cout << endl;
// 将数字转换为字符串
vector<string> strNumbers;
transform(numbers.begin(), numbers.end(), back_inserter(strNumbers),
[](int n) { return "数字" + to_string(n); });
cout << "字符串形式: ";
for (const auto& str : strNumbers) cout << str << " ";
cout << endl;
return 0;
}
总结
vector 的优点:
- 动态大小:无需预先指定大小
- 快速随机访问:支持 O(1) 时间复杂度的索引访问
- 内存连续:缓存友好,访问效率高
- 丰富的接口:提供了多种操作函数
- 类型安全:模板确保类型安全
vector 的缺点:
- 中间插入/删除较慢:需要移动后续元素
- 重新分配成本:当容量不足时,需要重新分配内存并复制元素
使用建议:
- 需要频繁随机访问时使用 vector
- 主要在尾部添加/删除元素时使用 vector
- 如果需要频繁在头部或中间插入,考虑使用 deque 或 list
- 使用
reserve()预留容量以减少重新分配次数 - 使用
emplace_back()替代push_back()以提高效率
vector 是 C++ 中最常用的容器之一,掌握它的使用对于编写高效、现代的 C++ 代码非常重要。