vector(下)

1.常见接口使用

初始化 vector

使用 std::vector 需要包含头文件 <vector>。初始化可以通过多种方式完成:

cpp 复制代码
#include <vector>
std::vector<int> vec1; // 空 vector
std::vector<int> vec2(5, 10); // 5 个元素,每个值为 10
std::vector<int> vec3 = {1, 2, 3, 4, 5}; // 初始化列表

添加元素

使用 push_back 在末尾添加元素:

cpp 复制代码
vec1.push_back(6); // vec1 现在为 {6}

使用 emplace_back 避免临时对象构造:

cpp 复制代码
vec1.emplace_back(7); // vec1 现在为 {6, 7}

访问元素

通过下标或 at 访问元素:

cpp 复制代码
int val1 = vec3[2]; // val1 = 3
int val2 = vec3.at(3); // val2 = 4

使用 frontback 访问首尾元素:

cpp 复制代码
int first = vec3.front(); // first = 1
int last = vec3.back(); // last = 5

修改元素

通过下标或迭代器修改元素:

cpp 复制代码
vec3[1] = 20; // vec3 现在为 {1, 20, 3, 4, 5}

删除元素

使用 pop_back 删除末尾元素:

cpp 复制代码
vec3.pop_back(); // vec3 现在为 {1, 20, 3, 4}

使用 erase 删除指定位置元素:

cpp 复制代码
vec3.erase(vec3.begin() + 1); // vec3 现在为 {1, 3, 4}

容量操作

检查 vector 是否为空:

cpp 复制代码
bool isEmpty = vec1.empty(); // isEmpty = false

获取 vector 大小和容量:

cpp 复制代码
size_t size = vec3.size(); // size = 3
size_t capacity = vec3.capacity(); // 当前分配的存储空间

调整 vector 大小:

cpp 复制代码
vec3.resize(5); // vec3 现在为 {1, 3, 4, 0, 0}

迭代器操作

使用迭代器遍历 vector

cpp 复制代码
for (auto it = vec3.begin(); it != vec3.end(); ++it) {
    std::cout << *it << " ";
}

使用范围 for 循环:

cpp 复制代码
for (int num : vec3) {
    std::cout << num << " ";
}

清空 vector

使用 clear 清空所有元素:

cpp 复制代码
vec3.clear(); // vec3 现在为空

交换 vector

使用 swap 交换两个 vector 内容:

cpp 复制代码
std::vector<int> vec4 = {10, 20};
vec3.swap(vec4); // vec3 现在为 {10, 20}, vec4 为空

2.vector 迭代器失效问题

迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对指针进行了封装,比如:vector的迭代器就是原生态指针T* 。因此迭代器失效,实际就是迭代器底层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间,造成的后果是程序崩溃(即如果继续使用已经失效的迭代器,程序可能会崩溃)。

核心本质:vector 底层是连续动态数组,当内存重新分配、元素移动后,原迭代器指向的位置 / 内存无效,再使用就会崩溃、乱码。

场景 1:扩容操作 → 所有迭代器全部失效

触发条件执行 push_back / insert / reserve / resize 时,当前容量不足,vector 会:
开辟一块新的更大内存把旧数据拷贝到新内存释放旧内存。
后果:所有旧迭代器变成野指针,完全失效。
错误代码

cpp 复制代码
vector<int> v = {1,2,3};
auto it = v.begin(); // 指向旧内存

v.push_back(4); // 容量不足,触发扩容,旧内存被释放!

// it 已经是野指针,访问崩溃
cout << *it << endl; 

解决方案

扩容后重新获取迭代器:

cpp 复制代码
auto it = v.begin();
v.push_back(4);
it = v.begin(); // 重新赋值,指向新内存
场景 2:insert 插入元素 → 插入位置及之后的迭代器失效

触发条件:在任意位置插入元素(即使不扩容),插入位置后面的所有元素会整体向后移动。
后果:插入位置及之后的迭代器,指向的元素位置已经改变,直接失效。

cpp 复制代码
vector<int> v = {1,2,3};
auto it = v.begin() + 1; // 指向 2

v.insert(it, 10); // 插入后,元素后移,it 失效

// 访问失效迭代器,未定义行为
cout << *it << endl;

解决方案:

insert 会返回新的有效迭代器,用它覆盖旧迭代器:

cpp 复制代码
it = v.insert(it, 10); // 用返回值更新迭代器
场景 3:erase 删除元素 → 删除位置及之后的迭代器失效

触发条件:删除元素后,删除位置后面的所有元素会整体向前移动。

后果:删除位置及之后的迭代器直接失效。

⚠️ 经典坑:循环删除元素时直接 it++,必崩溃!

错误代码(循环删除偶数,必错)

cpp 复制代码
vector<int> v = {1,2,3,4};
for(auto it = v.begin(); it != v.end(); it++){
    if(*it % 2 == 0){
        v.erase(it); // 删除后 it 失效,再 it++ 直接崩溃
    }
}

解决方案

erase 会返回下一个有效迭代器,直接赋值即可:

cpp 复制代码
for(auto it = v.begin(); it != v.end(); ){
    if(*it % 2 == 0){
        it = v.erase(it); // 用返回值更新,不用手动++
    }else{
        it++; // 不删除时再++
    }
}

总结(必背)

1.扩容 → 全部迭代器失效 → 重新获取。

2.插入 / 删除 → 操作位置及之后失效 → 用 insert/erase 返回值更新。

3.迭代器使用原则:只要修改了 vector 结构(增删扩容),就不要使用旧迭代器。
谢谢

相关推荐
Jack2015 小时前
HarmonyOS开发中错误处理策略:网络异常统一处理
算法
小小杨树17 小时前
读懂色彩:拍照调色不再难
算法·计算机视觉·配色
JieE2121 天前
LeetCode 226. 翻转二叉树|JS 递归超详细拆解,二叉树入门经典题
javascript·算法
JieE2121 天前
LeetCode 104. 二叉树的最大深度|递归思路超详细拆解
javascript·算法
vivo互联网技术2 天前
CVPR 2026 | 全新强化学习框架 BeautyGRPO:重塑真实人像
算法·大模型·cvpr·影像
Darling噜啦啦2 天前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试
用户497863050732 天前
(一)小红的数组操作
算法·编程语言
怕浪猫2 天前
Electron 系列文章封面图
算法·架构·前端框架
徐小夕2 天前
JitWord 3.0 正式发布,高精度Word异构解析+复杂组件兼容,打造web端协同Word编辑器
前端·vue.js·算法