Loading...
墨滴

苏小迪

2021/05/25  阅读:35  主题:全栈蓝

CPP vector遍历删除

erase

erase这个方法有点诡异,在循环中使用erase时稍微不注意可能就会出现错误,在循环体中用erase时,我们习惯让iterator增加,但实际上调用erase时,本身就已经自动让iterator增加了,如果for循环再增加就会增加两次,这样就会出现错误。

#include <vector>
#include <iostream>
using namespace std;
 
int main(void)
{
        vector<int> vec;
        for (int i = 0; i<10;i++)
        {
                vec.push_back(i);
        }
        for(auto it  = vec.begin(); it != vec.end(); /*it++*/)
         {
                 cout<<"correct erase:"<<*(it)<<endl;
                 it = vec.erase(it);
        }

         return 0;
 } 

上面这段代码是在遍历的过程中删除元素的正确操作。输出如下:

codemaxi@codemaxi-PC:~/cpp$ g++ vector_erase.cpp 
codemaxi@codemaxi-PC:~/cpp$ ./a.out 
correct erase:0
correct erase:1
correct erase:2
correct erase:3
correct erase:4
correct erase:5
correct erase:6
correct erase:7
correct erase:8
correct erase:9
codemaxi@codemaxi-PC:~/cpp$ 

但是下面这段是错误的。通过输出可以看到漏了一半的元素,it增加了两次,for循环中一次,erase一次。

#include <vector>
#include <iostream>
using namespace std;
 
int main()
{
        vector<int> vec;
        for (int i = 0; i<10;i++)
        {
                vec.push_back(i);
        }
        for(auto it  = vec.begin(); it != vec.end(); ++it)
         {
                 cout<<"incorrect erase:"<<*(it)<<endl;
                 vec.erase(it);
        }
         return 0;
 } 

输出如下:

codemaxi@codemaxi-PC:~/cpp$ g++ vector_erase.cpp 
codemaxi@codemaxi-PC:~/cpp$ ./a.out 
incorrect erase:0
incorrect erase:2
incorrect erase:4
incorrect erase:6
incorrect erase:8
codemaxi@codemaxi-PC:~/cpp$ 

我们来看下erase的函数原型:

iterator erase (const_iterator position);
iterator erase (const_iterator first, const_iterator last);

从vector中删除一个元素(position),或者范围元素( [first, last) )

  • 参数:

position : iterator 指向vector 中要删除元素的位置。

iterator first,last : iterator指向要删除范围。

  • 返回值:

返回一个iterator ,指向删除元素的下一个元素。所以在用for循环删除元素时,迭代器不用++指向下一个元素,erase()执行后,自动返回一个迭代器指向下一个元素。

  • 原文是:

An iterator pointing to the new location of the element that followed the last element erased by the function call. This is the container end if the operation erased the last element in the sequence.

所以切忌:使用vector erase删除元素时一定不能再使用++了,因为erase本身就会返回删除元素的下一个元素。

revome

说了erase就顺便说以下remove吧,首先remove并不是vector的成员函数,他的原型:

iterator remove(iterator first, iterator last,val);

STL中remove()只是将待删除元素之后的元素移动到vector的前端,而不是删除。若要真正移除,需要搭配使用erase()。

我们来看看remove函数的源码,

template <class ForwardIteratorclass T>
ForwardIterator remove (ForwardIterator firstForwardIterator lastconst Tval)
{

    ForwardIterator result = first;
    while (first!=last) 
    {
        if (!(*first == val)) 
        {
            *result = move(*first); //first中的值被移到result中,first变为unspecified
            ++result;
        }
        ++first;
    }
    return result;
}

remove的时候只是通过迭代器的指针向前移动来删除,将没有被删除的元素放在链表的前面,并返回一个指向新的超尾值的迭代器。由于remove()函数不是vector成员函数,因此不能调整vector容器的长度。(对vector来说)remove()函数并不是真正的删除,要想真正删除元素则需要使用erase()或者resize()函数。

#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;
 
int main(void)
{
        vector<int> vec;
        for (int i = 0; i<10;i++)
        {
                vec.push_back(i);
        }

        remove(vec.begin(), vec.end(), 3);
        remove(vec.begin(), vec.end(), 6);

        for(auto it  = vec.begin(); it != vec.end(); it++)
         {
                 cout<<"after remove:"<<*(it)<<endl;
        }

         return 0;
 } 

输出:

codemaxi@codemaxi-PC:~/cpp$ g++ vector_remove.cpp 
codemaxi@codemaxi-PC:~/cpp$ ./a.out 
after remove:0
after remove:1
after remove:2
after remove:4
after remove:5
after remove:7
after remove:8
after remove:9
after remove:9
after remove:9
codemaxi@codemaxi-PC:~/cpp$ 

执行remove之后返回新的end()迭代器,但是不改变原来数组的end()迭代器的值,将范围内值等于val的元素用后一个元素替代。也就是原先数组中新的end()至原end()范围内的值仍为原来数组的值(等于val的值),但是这部分状态不可靠。begin()到新的end()这部分是不等于val的值。

注意:remove之后并不减少vector的size

由此可以得到想要删除vector中的某个元素值可以像下面这样使用:

vec.erase(remove(vec.begin(), vec.end(), value), vec.end());

首先remove将value移除,然后remove函数返回一个新的end,也就是原来的end-1。所以上面的函数最后可以理解成(不能完全相等):

vec.erase(vec.end()-1, vec.end());

好了,今天的学习就到这里了。

苏小迪

2021/05/25  阅读:35  主题:全栈蓝

作者介绍

苏小迪