菜鸟教程 -- 学的不仅是技术,更是梦想!

C++ 教程
C++ 教程 C++ 简介 C++ 环境设置 C++ 基本语法 C++ 注释 C++ 数据类型 C++ 变量类型 C++ 变量作用域 C++ 常量 C++ 修饰符类型 C++ 存储类 C++ 运算符 C++ 循环 C++ 判断 C++ 函数 C++ 数字 C++ 数组 C++ 字符串 C++ 指针 C++ 引用 C++ 日期 & 时间 C++ 基本的输入输出 C++ 结构体(struct) C++ vector 容器 C++ 数据结构

C++ 面向对象

C++ 类 & 对象 C++ 继承 C++ 重载运算符和重载函数 C++ 多态 C++ 数据抽象 C++ 数据封装 C++ 接口(抽象类)

C++ 高级教程

C++ 文件和流 C++ 异常处理 C++ 动态内存 C++ 命名空间 C++ 模板 C++ 预处理器 C++ 信号处理 C++ 多线程 C++ Web 编程

C++ 资源库

C++ STL 教程 C++ 导入标准库 C++ 标准库 C++ 有用的资源 C++ 实例 C++ 测验 C++ <iostream> C++ <fstream> C++ <sstream> C++ <iomanip> C++ <array> C++ <vector> C++ <list> C++ <forward_list> C++ <deque> C++ <stack> C++ <queue> C++ <priority_queue> C++ <set> C++ <unordered_set> C++ <map> C++ <unordered_map> C++ <bitset> C++ <algorithm> C++ <iterator> C++ <functional> C++ <numeric> C++ <complex> C++ <valarray> C++ <cmath> C++ <string> C++ <regex> C++ <ctime> C++ <chrono> C++ <thread> C++ <mutex> C++ <condition_variable> C++ <future> C++ <atomic> C++ <type_traits> C++ <typeinfo> C++ <exception> C++ <stdexcept> C++ <cstdio> C++ <cstdint> C++ <memory> C++ <new> C++ <utility> C++ <random> C++ <locale> C++ <codecvt> C++ <cassert> C++ <cwchar> C++ <climits> C++ <cfloat> C++ <cstdlib> C++ <numbers> C++ OpenCV
(追記) (追記ここまで)

C++ vector 容器

在 C++ 中,vector 是最常用的 STL 容器之一。

vector 本质上是一个可自动扩容的动态数组,与传统数组相比,vector 不需要手动管理内存,可以根据元素数量自动扩容。

由于 vector 具有:

  • 连续内存存储
  • 随机访问速度快
  • STL 生态完整
  • 缓存友好(Cache Friendly)

因此,在现代 C++ 开发中,大部分顺序数据存储场景都会优先考虑 vector。

vector 的核心特点

  • 动态大小:vector 可以自动扩容和缩容。
  • 连续内存:元素在内存中连续存储,访问效率非常高。
  • 随机访问:支持通过下标快速访问元素,时间复杂度为 O(1)。
  • 自动内存管理:不需要手动 malloc/free。
  • 支持迭代器:可以方便地与 STL 算法配合使用。

为什么 vector 很快?

vector 的元素在内存中是连续排列的:

[1][2][3][4][5]

这种布局对 CPU Cache 非常友好。

CPU 在读取第一个元素时,通常会提前把后面的数据一起加载到缓存中,因此遍历 vector 的速度通常非常快。

这也是为什么很多情况下:

vector 比 list 更快

即使 list 在理论上的删除复杂度更低。

使用 vector

使用 vector 前,需要包含头文件:

#include <vector>

创建 vector

创建一个空 vector:

std::vector<int>vec;

指定初始大小:

std::vector<int>vec(5);

以上代码会创建 5 个元素,默认值为 0。

指定初始值:

std::vector<int>vec(5, 10);

创建结果:

[10, 10, 10, 10, 10]

使用初始化列表:

std::vector<int>vec = {1, 2, 3, 4};

添加元素

使用 push_back() 向尾部添加元素:

vec.push_back(100);

vector 尾部追加元素的平均时间复杂度为:

O(1)

访问元素

使用下标访问:

int x = vec[0];

使用 at():

int y = vec.at(1);

区别:

  • [] 不检查越界,速度更快。
  • at() 会检查越界,更安全。

获取大小

vec.size();

返回当前元素数量。

size 和 capacity 的区别

这是 vector 最重要的概念之一。

std::vector<int>vec;
vec.push_back(1);
vec.push_back(2);
std::cout << vec.size() << std::endl;
std::cout << vec.capacity() << std::endl;

输出可能为:

2
4
  • size:当前元素数量。
  • capacity:当前已分配的内存容量。

capacity 通常大于等于 size。

这是因为 vector 会提前申请更多空间,以减少频繁扩容。

vector 扩容机制

当 vector 空间不足时,会发生扩容:

  1. 申请更大的内存
  2. 复制旧元素
  3. 释放旧内存

这个过程代价较高。

例如:

std::vector<int>vec;
for (int i = 0; i < 1000000; i++) {
 vec.push_back(i);
}

可能发生多次内存重新分配。

reserve() 预分配空间

为了避免频繁扩容,可以提前分配内存:

std::vector<int>vec;
vec.reserve(1000000);

这样可以减少:

  • 内存重新分配
  • 元素复制
  • 性能损耗

这是工程开发中非常重要的优化技巧。

遍历 vector

使用下标

for (size_t i = 0; i < vec.size(); i++) {
 std::cout << vec[i] << " ";
}

使用迭代器

for (auto it = vec.begin(); it != vec.end(); ++it) {
 std::cout << *it << " ";
}

范围 for 循环

for (int element : vec) {
 std::cout << element << " ";
}

删除元素

删除第三个元素:

vec.erase(vec.begin() + 2);

注意:

vector 删除中间元素时,后面的元素会整体前移。

例如:

1 2 3 4 5
删除 2 后:
1 3 4 5

其中:

3 4 5

都需要移动位置。

因此:

erase() 的时间复杂度为 O(n)

vector 不适合的场景

  • 频繁头部插入
  • 频繁中间删除
  • 超大对象频繁扩容

例如:

vec.insert(vec.begin(), 100);

这是一个较慢的操作。

迭代器失效

vector 扩容后,原来的内存地址可能失效。

例如:

std::vector<int>vec = {1, 2, 3};
auto it = vec.begin();
vec.push_back(4);
std::cout << *it;

这里的 it 可能已经失效。

因为 push_back() 可能导致重新分配内存。

这是 vector 最常见的坑之一。

clear() 的注意事项

vec.clear();

clear() 只会清空元素:

  • size 变为 0
  • capacity 可能仍然保留

也就是说:

clear() 不一定释放内存

如果希望释放内存:

std::vector<int>().swap(vec);

或者:

vec.shrink_to_fit();

push_back 和 emplace_back

现代 C++ 更推荐使用:

emplace_back()

例如:

vec.push_back(Person("Tom", 20));

可能产生临时对象。

而:

vec.emplace_back("Tom", 20);

会直接在 vector 内部原地构造对象。

通常效率更高。

vector 与数组的区别

特性 数组 vector
大小固定
自动扩容
连续内存
随机访问
STL 支持 较少 完整
安全访问 at()

vector 常见操作复杂度

操作 时间复杂度
随机访问 O(1)
push_back 平均 O(1)
尾部删除 O(1)
头部插入 O(n)
中间删除 O(n)
clear O(n)

实例:学生成绩管理

实例


#include <iostream>
#include <vector>
#include <numeric>

int main() {
std::vector<int>scores = {85, 90, 78, 92};
scores.push_back(88);
std::cout << "所有成绩: ";
for (int score : scores) {
std::cout << score << " ";
}

std::cout << std::endl;
int total = std::accumulate(scores.begin(), scores.end(), 0);
double average = total * 1.0 / scores.size();
std::cout << "平均成绩: " << average << std::endl;
scores.erase(scores.begin() + 2);
std::cout << "删除后成绩: ";
for (int score : scores) {
std::cout << score << " ";
}

std::cout << std::endl;

return 0;
}

输出结果如下:

所有成绩: 85 90 78 92 88 
平均成绩: 86.6
删除后成绩: 85 90 92 88 

总结

vector 是现代 C++ 中最重要、最常用的数据结构之一。

它的核心优势:

  • 动态扩容
  • 连续内存
  • 随机访问快
  • 缓存友好
  • STL 生态完整

但同时也需要注意:

  • 扩容的性能代价
  • 中间删除效率低
  • 迭代器失效问题

对于绝大多数顺序存储场景:

vector 通常都是默认首选容器
AI 思考中...

2 篇笔记 写笔记

  1. #0

    Runoob2

    139***[email protected]

    362

    vector 容器也可以嵌套。如下实例:

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
     // 创建一个二维向量,用于存储乘法表
     vector<vector<int>> outer;
     
     // 生成乘法表
     for (int i = 1; i <= 10; i++) {
     // 创建一个一维向量,用于存储当前行的乘法结果
     vector<int> inner;
     for (int j = 1; j <= 10; j++)
     // 计算 i * j 的结果并添加到当前行向量中
     inner.push_back(i * j);
     
     // 将当前行向量添加到外层二维向量中
     outer.push_back(inner);
     }
     
     // 打印乘法表
     for (vector<vector<int>>::iterator iter = outer.begin(); iter != outer.end(); ++iter) {
     // 获取当前行的向量
     vector<int> inner = *iter;
     for (vector<int>::iterator it = inner.begin(); it != inner.end(); ++it)
     // 打印当前元素,设置宽度为 4 个字符,确保对齐
     cout << setw(4) << *it;
     // 打印换行符,开始新的一行
     cout << endl;
     }
     return 0;
    }

    Runoob2

    139***[email protected]

    2年前 (2024年08月13日)
  2. #0

    Cheng_Nice

    fic***[email protected]

    261

    无用嵌套,这样好费事,基于你的代码给你改进一下吧

    #include <bits/stdc++.h>
    using namespace std;
    int main()
    {
     // 定义一个整数向量 inner,用于存储乘法表的每一项
     vector<int> inner;
     // 计数器 count,用于追踪输出向量中的元素位置
     int count = 0;
     
     // 生成 1 到 9 的乘法表
     for (int i = 1; i < 10; i++) {
     // 内层循环,用于输出每一行的乘法结果
     for (int j = 1; j <= i; j++) {
     inner.push_back(i * j); // 将乘法结果存储到 inner 向量中
     cout << setw(4) << inner[count++]; // 输出当前存储的乘法结果,格式化为宽度为 4 的字段
     }
     cout << endl; // 换行,开始输出下一行的乘法结果
     }
     system("pause"); // 暂停程序,等待用户按键
     return 0;
    }

    Cheng_Nice

    fic***[email protected]

    2年前 (2024年12月19日)

点我分享笔记

  • 昵称 (必填)
  • 邮箱 (必填)
  • 引用地址

AltStyle によって変換されたページ (->オリジナル) /