C++ vector 笔记

0 阅读8分钟

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 的优点:

  1. 动态大小:无需预先指定大小
  2. 快速随机访问:支持 O(1) 时间复杂度的索引访问
  3. 内存连续:缓存友好,访问效率高
  4. 丰富的接口:提供了多种操作函数
  5. 类型安全:模板确保类型安全

vector 的缺点:

  1. 中间插入/删除较慢:需要移动后续元素
  2. 重新分配成本:当容量不足时,需要重新分配内存并复制元素

使用建议:

  1. 需要频繁随机访问时使用 vector
  2. 主要在尾部添加/删除元素时使用 vector
  3. 如果需要频繁在头部或中间插入,考虑使用 deque 或 list
  4. 使用 reserve() 预留容量以减少重新分配次数
  5. 使用 emplace_back() 替代 push_back() 以提高效率

vector 是 C++ 中最常用的容器之一,掌握它的使用对于编写高效、现代的 C++ 代码非常重要。