使用小细节——C++ list的erase和remove


平时一般使用都是vector,但是涉及到频繁删除元素的时候,就会用到list,因为vector每次删除后,删除元素后面的每个元素的迭代器都要重新分配,导致效率低下,而且十分麻烦。但是list使用erase和remove删除元素时,也会存在很多坑。
一下是之前一篇博文中的vector和list删除元素的时间效率比较:

每个测试数据下面的第一行,第二行分别是vector和list
10:
Used time is  = 16ms
Used time is  = 12ms
 100:
Used time is  = 526ms
Used time is  = 89ms
 1000:
Used time is  = 28242ms
Used time is  = 1334ms
 10000:
 Used time is  = 2532717ms
 Used time is  = 13984ms
 */
————————————————
版权声明:本文为CSDN博主「繁星蓝雨」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_33375598/article/details/104778027

1 erase(搭配迭代器)

    list<int> List;
    List.push_back(1);
    List.push_back(1);
    List.push_back(3);
    List.push_back(1);
    List.push_back(1);
    List.push_back(5);
    List.push_back(1);
    List.push_back(1);
    for (list<int>::iterator i = List.begin(); i != List.end(); ++i) {
        if(*i == 1){
            List.erase(i);
        }
    }
    for (list<int>::const_iterator i = List.begin(); i != List.end(); ++i) {
        if(i != List.begin()) cout <<" ";
        cout << *i;
    }

上面的代码,大家可能以为会输出1 3 1 5 1

因为大家会认为删除list的一个迭代器后,会让迭代器指向下一个,然后for循环的条件i++,迭代器再往后移动一次,连续的1就会被跳过。 (不成立)

但是实际上会输出:
在这里插入图片描述
但是实际上,list使用erase删除一个迭代器后,会保留原始索引,仍能输出删除迭代器所指的值,使用erase后返回的是下一个迭代器。
测试程序:

    list<int> List;
    List.push_back(1);
//    List.push_back(1);
    List.push_back(3);
    List.push_back(1);
    List.push_back(1);
    List.push_back(5);
    List.push_back(1);
    List.push_back(1);
    for (list<int>::iterator i = List.begin(); i != List.end(); ++i) {

        if(*i == 1){
            list<int>::iterator temp  = List.erase(i);
            cout << "temp:" << *temp <<" ";
            cout << "i:"<<*i <<" ";
        }
    }

输出:
在这里插入图片描述
结论是:使用erase后,当前的迭代器不会自动+1。

2 remove(搭配值)

一开始我以为remove(value)只是删除第一个查询到的value,但是实际上它会删除容器中所有value,因此不需要使用for循环,即可删除容器中所有等于value的值。

但是使用remove(value)后,会立即使所有值为value的迭代器全部失效,结果就是,当你再使用失效迭代器时,程序就会报错。

  list<int> List;
    List.push_back(1);
//    List.push_back(1);
    List.push_back(3);
    List.push_back(1);
    List.push_back(1);
    List.push_back(5);
    List.push_back(1);
    List.push_back(1);
    for (list<int>::iterator i = List.begin(); i != List.end(); ++i) {
        cout << "test:" << *i;
        List.remove(1);
    }

编译不报错,但是逐步调试就会发现错误:
在这里插入图片描述
原因就是使用了失效的迭代器。

3 在while来使用erase

举例(源自自己的一篇博文:https://blog.csdn.net/qq_33375598/article/details/104778027):

list<int> List, fail;
list<int>::iterator iter = List.begin();
    while(iter != List.end()){
        if(fgrade(*iter)){
            fail.push_back(*iter);
            iter = List.erase(iter);
        }else{
            ++iter;
        }
    }
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

繁星蓝雨

如果觉得文章不错,可以请喝咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值