题目
使用 vector 删除特定条件的元素
信息
- 类型:问答
- 难度:⭐
考点
vector 基本操作, 迭代器失效问题, 删除元素的标准方法
快速回答
正确删除 vector 中元素的标准方法是使用 Erase-Remove 惯用法:
- 使用
std::remove_if算法将需要保留的元素移动到容器前部 - 配合
vector::erase删除尾部多余元素
错误做法是直接使用迭代器循环删除,这会导致迭代器失效:
// 错误示例(迭代器失效)
for(auto it = vec.begin(); it != vec.end(); ++it) {
if(*it % 2 == 0) {
vec.erase(it); // 此处 it 失效
}
}
## 解析
问题场景
给定一个整数 vector,要求删除其中所有偶数元素。例如:输入 {1, 2, 3, 4, 5},输出 {1, 3, 5}。
原理说明
在 vector 中删除元素时需注意两个关键点:
- 迭代器失效:调用
erase()后,被删除元素及其后的所有迭代器都会失效 - 高效操作:vector 尾部插入/删除高效,但中间删除会导致元素移动
正确解决方案
使用 Erase-Remove 惯用法(C++11 起):
#include <algorithm>
#include <vector>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
// 1. 使用 remove_if 将偶数移到末尾
auto new_end = std::remove_if(vec.begin(), vec.end(),
[](int n) { return n % 2 == 0; });
// 2. 删除末尾的无效元素
vec.erase(new_end, vec.end());
// 结果:vec = {1, 3, 5}
}最佳实践
- C++20 优化:使用
std::erase_if更简洁std::erase_if(vec, [](int n) { return n % 2 == 0; }); - Lambda 表达式:灵活定义删除条件
- 性能考量:时间复杂度 O(n),只需一次元素遍历
常见错误
- 迭代器失效陷阱:在循环中直接使用
erase()后继续使用原迭代器 - 错误修正尝试:以下写法仍存在缺陷
// 危险!可能遗漏连续偶数 for(auto it = vec.begin(); it != vec.end(); ) { if(*it % 2 == 0) { it = vec.erase(it); // 正确获取返回值但效率低 } else { ++it; } } - 无效索引法:从后向前遍历索引仍会导致多次数据移动
扩展知识
- 其他容器差异:
- list 可直接使用
remove_if成员函数(效率更高) - map/set 在循环中使用
erase(it++)是安全的
- list 可直接使用
- 算法原理:
remove_if通过双指针实现:- 第一个指针遍历所有元素
- 第二个指针指向下一个保留位置
- 最终返回保留区的结束迭代器
- 性能对比:Erase-Remove 比循环删除快 5-10 倍(避免重复移动元素)