vector/list/map/set的插入、删除、遍历 - remove\erase函数

1、vector中删除满足某些条件的元素和迭代器失效问题

#include <iostream>
#include <vector>
using namespace std;
int main()
{
    std::vector<int> mVector;
    mVector.push_back(1);   //插入元素push_back
    mVector.push_back(2);
    mVector.push_back(0);
    mVector.push_back(3);
    mVector.push_back(4);
    mVector.push_back(0);
    mVector.push_back(0);
    mVector.push_back(6);
    mVector.push_back(0);
    mVector.push_back(0);

    std::vector<int>::iterator iter = mVector.begin();
    for (; iter != mVector.end(); )  //删除操作
    {
        if (0 != *iter)
        {
            ++iter;
        }
        else
        {
            iter = mVector.erase(iter);     //方式一(正确)           
            //mVector.erase(iter++);        //方式二(错误)
            //mVector.erase(it);  it++;     //方式三(错误)
        }

    for (iter = mVector.begin();; iter != mVector.end(); ++iter)//vector遍历操作
    {
        std::cout << " " << *iter << " ";
    }
    return 0;
}
【错误分析】
/*方式三:错误
    vv.erase(it); //对vector进行增加删除等操作后之前it可能无效
    it++; //删除后it此时已经无效,it成为野指针,不能执行it++操作
/*方式二:错误
    该种情况,vector、deque不能用,但是list、map、set可以!

2、list中删除满足某些条件的元素

#include <iostream>
#include <list>
using namespace std;
int main()
{
    std::list<int> mList;
    mList.push_back(1); //插入操作push_back
    mList.push_back(2);
    mList.push_back(0);
    mList.push_back(3);
    mList.push_back(4);
    mList.push_back(0);
    mList.push_back(0);
    mList.push_back(6);
    mList.push_back(0);
    mList.push_back(0);

    std::list<int>::iterator iter = mList.begin();
    for (; iter != mList.end(); ) //删除操作
    {
        if (0 != *iter)
        {
            ++iter;
        }
        else
        {
            iter = mList.erase(iter);  //方式一(正确)
            //mList.erase(iter++);     //方式二(正确)
            //mList.erase(iter);  iter++;     //方式三(错误)
        }
    }

    iter = mList.begin();
    for (; iter != mList.end(); ++iter) //遍历操作
    {
        std::cout << " " << *iter << " ";
    }
    return 0;
}

3、map中删除满足某些条件的元素
注意:对map和set等自动排序的容器不应使用remove一类算法

#include <iostream>
#include <string> 
#include <map>
using namespace std;
int main(int argc, char* argv[])  
{  
    map<int, string> mapData;  
//插入元素方式(四种)
    mapData.insert(pair<int,string>(0,"aaa"));
    mapData[1] = "bbb";   
    mapData.insert(make_pair<int,string>(2,"ccc"));
    mapData.insert(map<int,string>::value_type(3,"ddd"));

    for (map<int, string>::iterator it=mapData.begin(); it!=mapData.end(); /*it++*/)  //删除操作
    {  
        if ((*it).first == 2)  
        {  
            it = mapData.erase(it); //方式一(正确)
            //mapData.erase(it++);  //方式二(正确)
            //mVector.erase(it);  it++;     //方式三(错误)
        }  
        else  
        {  
            it++;  
        }  
    }  
    for (map<int, string>::iterator it=mapData.begin(); it!=mapData.end(); it++)  //map遍历输出
    {
        cout<<(*it).first<<"   "<<(*it).second<<endl;  //取值操作方式 (*it).first和(*it).second
    }
    return 0;  
}   

3、set中删除满足某些条件的元素

#include<iostream>  
#include<set>  
using namespace std;  
int main()  
{  
    set<int> s;  
    s.insert(5); //第一次插入5,可以插入  
    s.insert(1);  
    s.insert(0);  
    s.insert(3);  
    s.insert(5); //第二次插入5,重复元素,不会插入  
    s.erase(-1);   

    set<int>::iterator it = s.begin();  
    for(;it != s.end();)  //删除操作
    {
        if(*it < 2)
        {
            //it = s.erase(it); //方式一(正确)
            //s.erase(it++);    //方式二(正确)
            //s.erase(it); it++; //方式三(错误)
        }
        else
            it++;
    }

    for(it = s.begin(); it != s.end(); it++)  //遍历操作
        cout << *it << " ";  
    return 0;  
}  

综上所述,
对于删除操作:
方式一都正确;
方式三都错误;
方式二vector/deque等顺序容器错误、list/map/set等关联容器正确。

>

【重点:remove和erase讲解】
1、 erase一般作为一个container的成员函数,是真正删除的元素,是物理上的删除。
2、作为算法项目组的remove类函数,是逻辑上的删除,将被删除的元素移动到容器末尾,然后返回新的末尾,此时容器的size不变更。
3、项目组容器若有成员函数remove,那么代表的是真正物理意义上的删除元素。
4、若是该容器是vector、string或者deque,应用erase-remove idiom或者erase-remove_if idiom。
5、若是该容器是list,应用list::remove或者list:remove_if成员函数。
6、 若是该容器是一个联合 container,应用asso_con::erase成员函数或者remove_copy_if连络swap等体式格式。
7、有一些斗劲特别的容器具现,比如vector等,暂不推敲。

【remove和erase对比】 一般情况下,remove是STL的函数,#include < algorithm >,而erase是容器的成员函数,#include <容器> 。 使用remove不能真正的删除元素!
如果你真的要删除东西的话,可以用下面两种形式:erase-remove、erase。

vector<int> v;
v.erase(remove(v.begin(), v.end(), 99), v.end());//删除容器v中的所有的值为99的元素

//[总结]
//使用的固定形式:
//v.erase(remove(v.begin(), v.end(), VALUE), v.end());
//这句的意思是,取得VALUE的位置(位于结尾),然后删除VALUE到原vector结尾的所有元素
    // remove all elements from Numbers that match 10  
    vector<int>::iterator ret = remove(Numbers.begin(), Numbers.end(), 10) ;

【解释】原vector { 10 20 10 15 12 7 9 },删除10,会将10后面的元素移动到前面
(注意以下逐个元素对齐,模拟元素在内存中的位置,这样就容易看出变化规律)
原vector
10 20 10 15 12 7 9
遇到第一个10,数组变成
20    10 15 12 7 9
遇到第二个10移动到7 9之后又遇到第三个10于是剩下内存中未移动的7 9
20 15 12  7   9  7 9 
遇到第三个10
20 15 12  7   9  7 9 

但是,有特例— — list容器**
对于list,因为list有成员函数remove,因此调用list的remove成员函数可以“真的”删除,且比应用erase-remove惯用法更高效!

list<int> li;           // 建立一个list
                        // 放一些值进去
li.remove(99);          // 除去所有等于99的元素
                        // 真的删除值为99的元素
                        // 所以list的大小可能改变了
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值