C++ 从向量中删除元素

C++ 从向量中删除元素,c++,vector,stl,erase,C++,Vector,Stl,Erase,我想使用擦除方法从向量中清除一个元素。但这里的问题是,不能保证元素在向量中只出现一次。它可能会出现多次,我需要清除所有这些。我的代码是这样的: void erase(std::vector<int>& myNumbers_in, int number_in) { std::vector<int>::iterator iter = myNumbers_in.begin(); std::vector<int>::iterator endIt

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

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;
}
void擦除(std::vector&myNumbers\u in,int number\u in)
{
std::vector::iterator iter=myNumbers_in.begin();
std::vector::迭代器endIter=myNumbers_in.end();
对于(;iter!=endIter;++iter)
{
如果(*iter==数字_in)
{
myNumbers_in.擦除(iter);
}
}
}
int main(int argc,char*argv[])
{
std::向量myNmbers;
对于(int i=0;i<2;++i)
{
myNmbers.推回(i);
myNmbers.推回(i);
}
擦除(myNmbers,1);
返回0;
}

这段代码显然崩溃了,因为我在遍历向量时更改了向量的结尾。实现这一目标的最佳方式是什么?也就是说,是否有任何方法可以在不多次遍历向量或创建多个向量副本的情况下执行此操作?

调用erase将使迭代器无效,您可以使用:

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;
        }
    }

}
void擦除(std::vector&myNumbers\u in,int number\u in)
{
std::vector::iterator iter=myNumbers_in.begin();
while(iter!=myNumbers\u in.end())
{
如果(*iter==数字_in)
{
iter=我的数字\u英寸擦除(iter);
}
其他的
{
++iter;
}
}
}
或者可以与函子和std::vector::erase一起使用:

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());
struct橡皮擦
{
橡皮擦(int number_in):number_in(number_in){
int数_in;
布尔运算符()(int i)常量
{
返回i==中的数字_;
}
};
std::向量mynumber;
myNumbers.erase(std::remove_if(myNumbers.begin()、myNumbers.end()、橡皮擦(number_in))、myNumbers.end());
在这种情况下,您可以使用以下命令,而不是编写自己的函子:

std::vector myNumbers;
删除(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());
std::vector myNumbers;
myNumbers.erase(std::remove_if(myNumbers.begin(),myNumbers.end(),[number_in](int number){return number==number_in;}),myNumbers.end());
< C++ > 17中,也可以使用,在C++ 20中,这些(最后)被重命名为(和:注意:在Visual Studio 2019中,您需要将C++语言版本更改为最新的实验版本以支持):

std::vector myNumbers;
标准::擦除_if(我的数字,擦除器(数字_in));//或者使用lambda
或:

std::vector myNumbers;
标准::擦除(myNumbers,number_in);
使用:

std::vector&vec=myNumbers;//使用较短的名称
向量擦除(std::remove(vec.begin(),vec.end(),number_in),vec.end());

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

根据执行此操作的原因,使用a可能比std::vector更好

它只允许每个元素出现一次。如果您多次添加它,那么无论如何只会有一个实例需要删除。这将使擦除操作变得微不足道。 擦除操作的时间复杂度也比向量上的要低,但是,在集合上添加元素的速度较慢,因此可能没有多大优势

如果您对元素添加到向量的次数或元素添加的顺序感兴趣,那么这当然不起作用

  • 您可以使用索引访问进行迭代

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

  • 代码:


    要删除第一个元素,可以使用:

    vector<int> mV{ 1, 2, 3, 4, 5 }; 
    vector<int>::iterator it; 
    
    it = mV.begin(); 
    mV.erase(it); 
    
    向量mV{1,2,3,4,5};
    向量::迭代器;
    it=mV.begin();
    mV.擦除(它);
    
    既然可以使用equal_to,为什么还要使用自己的函子-P顺便说一句,用
    remove
    调用
    erase
    是执行此操作的标准方法。我想他就是这么做的。但如果使用自己的函子iirc,他应该使用remove_。或者只使用remove而不使用functor+1。拼写出来的代码在一次编程竞赛中帮助了我,而“只使用remove-erase惯用法”没有帮助。
    std::remove()
    移动元素,以便覆盖要删除的元素。该算法不会改变容器的大小,如果
    n
    元素被删除,那么最后的
    n
    元素是什么是未定义的。擦除-删除习惯用法在《有效STL:50改进标准模板库使用的具体方法》一书的第32项中有描述STL像这样的“习惯用法”使我在小项目中使用Python。@LouisDionne指的是一个迭代器重载,我使用的是两个迭代器重载overload@TamaMcGlinn,此代码不会删除
    end()
    它会删除
    begin()
    end()
    之间的范围。如果
    begin()
    等于
    end()
    ,则该范围内的元素为零,并且没有任何元素被删除(与
    擦除
    相同)。这不是问题所在。你11年后的答案似乎不相关,阿米特!
    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());
    
    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);
    }
    
    #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());
    }
    
    vector<int> mV{ 1, 2, 3, 4, 5 }; 
    vector<int>::iterator it; 
    
    it = mV.begin(); 
    mV.erase(it);