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

相关推荐
Tisfy8 小时前
LeetCode 1288.删除被覆盖区间:排序(非二重循环暴力)
算法·leetcode·题解·排序
Σίσυφος19008 小时前
激光三角 光平面标定之后计算深度图
算法·平面
阿文的代码库8 小时前
经典算法题剖析:按奇偶排序数组
数据结构·算法
AI小码8 小时前
WAIC 2026前瞻:AI产业进入拼落地的下半场
人工智能·算法·ai·程序员·大模型·编程·智能体
珠海西格电力9 小时前
零碳园区数据应用的具体场景有哪些?
大数据·人工智能·算法·架构·能源
geovindu9 小时前
CSharp: Dijkstra Algorithms
开发语言·后端·算法·c#
学逆向的10 小时前
汇编——位运算
开发语言·汇编·算法·网络安全
可编程芯片开发10 小时前
基于simulink的PEM燃料电池控制系统建模与仿真,对比PID,积分分离以及滑模控制器
算法
学究天人10 小时前
数学公理体系大全:Comprehensive Collection of Mathematical Axiom Systems(卷2)
算法·数学建模·动态规划·图论·抽象代数·拓扑学
玛卡巴卡ldf11 小时前
【LeetCode 手撕算法】(细节知识点总结)
java·数据结构·算法·leetcode·力扣