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 结构(增删扩容),就不要使用旧迭代器。
谢谢

相关推荐
鹿角片ljp10 小时前
LeetCode 46. 全排列|吃透回溯
算法·leetcode·职场和发展
鼎艺创新科技10 小时前
不依赖 UE/Unity:我们如何从零搭建一套国产三维 GIS 渲染引擎
人工智能·算法·unity·游戏引擎·三维电子沙盘
石头猫灯11 小时前
WordPress wp2shell 漏洞链完整拆解流程
网络·数据结构·安全·web安全
.道阻且长.13 小时前
11.LeetCode算法习题讲解--滑动窗口--将x减到0的最小操作数
算法·leetcode·职场和发展
wenyq713 小时前
LeetCode 2460. Apply Operations to an Array
算法·leetcode
.格子衫.14 小时前
032动态规划之区间DP——算法备赛
算法·动态规划
小欣加油15 小时前
leetcode3069 将元素分配到两个数组中I
数据结构·c++·算法·leetcode·职场和发展
不会代码的小猴15 小时前
7. JSON
开发语言·c++·笔记·qt·算法·json
怪奇云呼军15 小时前
知识库也会注入指令?闪电智能VoiceAgent 如何防住 Prompt Injection
人工智能·python·算法·云计算·音视频
阿里云大数据AI技术16 小时前
基于 EMR Serverless Ray 实现 Qwen 模型批量推理实践
人工智能·算法·agent