从向量中删除元素

我想清除一个元素从矢量使用擦除方法。但这里的问题是,元素不能保证只在向量中出现一次。它可能出现多次,我需要清除所有。我的代码是这样的:

void erase(std::vector<int>& myNumbers_in, int number_in)
{
std::vector<int>::iterator iter = myNumbers_in.begin();
std::vector<int>::iterator endIter = myNumbers_in.end();
for(; iter != endIter; ++iter)
{
if(*iter == number_in)
{
myNumbers_in.erase(iter);
}
}
}


int main(int argc, char* argv[])
{
std::vector<int> myNmbers;
for(int i = 0; i < 2; ++i)
{
myNmbers.push_back(i);
myNmbers.push_back(i);
}


erase(myNmbers, 1);


return 0;
}

这段代码显然崩溃了,因为我在迭代时改变了向量的结尾。实现这一目标的最佳方法是什么?也就是说,有没有什么方法可以避免对向量进行多次迭代或者再创建一个向量副本呢?

152556 次浏览

调用擦除将使迭代器失效,您可以使用:

void erase(std::vector<int>& myNumbers_in, int number_in)
{
std::vector<int>::iterator iter = myNumbers_in.begin();
while (iter != myNumbers_in.end())
{
if (*iter == number_in)
{
iter = myNumbers_in.erase(iter);
}
else
{
++iter;
}
}


}

或者你可以将 Move _ if与函数和 std: : Vector: : 擦除一起使用:

struct Eraser
{
Eraser(int number_in) : number_in(number_in) {}
int number_in;
bool operator()(int i) const
{
return i == number_in;
}
};


std::vector<int> myNumbers;
myNumbers.erase(std::remove_if(myNumbers.begin(), myNumbers.end(), Eraser(number_in)), myNumbers.end());

在这种情况下,您可以使用 移除代替编写自己的函数:

std::vector<int> myNumbers;
myNumbers.erase(std::remove(myNumbers.begin(), myNumbers.end(), number_in), myNumbers.end());

在 C + + 11中,你可以使用 lambda 代替函数:

std::vector<int> myNumbers;
myNumbers.erase(std::remove_if(myNumbers.begin(), myNumbers.end(), [number_in](int number){ return number == number_in; }), myNumbers.end());

在 C + + 17中,擦除实验性的: : 擦除 _ 如果也是可用的,在 C + + 20中,它们(最终)被重命名为 删除擦除 _ if(注意: 在 VisualStudio2019中,为了获得支持,需要将 C + + 语言版本更改为最新的实验版本) :

std::vector<int> myNumbers;
std::erase_if(myNumbers, Eraser(number_in)); // or use lambda

或:

std::vector<int> myNumbers;
std::erase(myNumbers, number_in);

使用 删除/删除成语:

std::vector<int>& vec = myNumbers; // use shorter name
vec.erase(std::remove(vec.begin(), vec.end(), number_in), vec.end());

所发生的情况是,remove压缩与 vector开始处要删除的值(number_in)不同的元素,并将迭代器返回到该范围之后的第一个元素。然后 erase删除这些元素(其值未指定)。

Depending on why you are doing this, using a 预备 might be a better idea than std::vector.

它允许每个元素只出现一次。如果您多次添加它,无论如何只有一个实例需要删除。这将使擦除操作变得微不足道。 The erase operation will also have lower time complexity than on the vector, however, adding elements is slower on the set so it might not be much of an advantage.

当然,如果您想知道一个元素被添加到向量中的次数或者元素被添加的顺序,那么这种方法就不起作用。

  1. 您可以使用索引访问进行迭代,

  2. 为了避免 O (n ^ 2)的复杂性 您可以使用两个索引,i-current 测试索引,j-index 来 存储下一项并在循环结束时新建向量的大小。

code:

void erase(std::vector<int>& v, int num)
{
size_t j = 0;
for (size_t i = 0; i < v.size(); ++i) {
if (v[i] != num) v[j++] = v[i];
}
// trim vector to new size
v.resize(j);
}

在这种情况下,迭代器没有失效,复杂度为 O (n) ,代码非常简洁,不需要编写一些助手类,尽管在某些情况下使用助手类可以使代码更灵活。

This code does not use erase method, but solves your task.

使用纯 stl,你可以按照以下方式来做(这与 Motti 的答案相似) :

#include <algorithm>


void erase(std::vector<int>& v, int num) {
vector<int>::iterator it = remove(v.begin(), v.end(), num);
v.erase(it, v.end());
}

C + + 20开始就有 擦除和 std: : 擦除 _ if,它结合了删除擦除的习惯用法。

std::vector<int> nums;
...
std::erase(nums, targetNumber);

或者

std::vector<int> nums;
...
std::erase_if(nums, [](int x) { return x % 2 == 0; });