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

相关推荐
z落落5 小时前
C# 冒泡排序+选择排序 + Array.Sort 自定义排序
数据结构·算法
wyy185100737285 小时前
双路并行:一套匹配算法如何解决中文制单的两大核心难题
算法·ai·crm·crm系统
s_w.h5 小时前
【 linux 】文件系统
linux·运维·服务器·算法·bash
无限进步_5 小时前
【C++】weak_ptr、循环引用与线程安全
开发语言·数据结构·c++·算法·安全
罗超驿5 小时前
9.LeetCode 209. 长度最小的子数组 | 滑动窗口专题详解
java·算法·leetcode·面试
水蓝烟雨6 小时前
0135. 分发糖果
算法·leetcode
IronMurphy6 小时前
【算法五十二】5. 最长回文子串
算法
guslegend6 小时前
第4讲:应用架构与代码组织
数据结构·人工智能·架构
Lewiis6 小时前
白话选择排序
数据结构·算法·排序算法