• STL中使用reverse_iterator时,如何正确使用erase函数


      假设有一个list容器,顺序存储了0-9一个10个整数。现在要使用reverse_iterator迭代器来查找值为8和5的元素,并且将这两个数删除。先来看以下的解决方法:

     1 #include <iostream>
     2 #include <list>
     3 using namespace std;
     4 int main()
     5 {
     6     //MergeSortTest(); // 测试题目一,归并排序
     7     //movableWindowsTest();// 测试题目二,移动窗口,输出窗口中的最小值
     8     list<int> l;
     9     for(int i = 0;i < 10;++i)
    10         l.push_back(i);// 初始化容器存入0-9十个整数
    11     list<int>::reverse_iterator it;
    12     int count = 2;// 记录剩下需要删除元素的个数
    13     for(it = l.rbegin();it != l.rend() && count; ++it)
    14     {
    15         if(*it == 8 || *it == 5)
    16         {
    17             list<int>::iterator temp(it.base());// 使用base函数返回一个普通迭代器,并以此删除指向的元素
    18             ++it;
    19             l.erase(temp);
    20             -- count;
    21         }
    22     }
    23     return 0;
    24 }

      我们重点看17-19行三行代码是否正确。这是我在不经过思考就顺手写出来的代码,这三行代码虽然编译可以通过,但是是错误的。

      首先,我们知道不可以直接使用reverse_iterator作为参数来调用erase函数的。

      (错误思路)我的初始思路是希望通过it.base()函数来返回一个普通迭代器,并使用普通迭代器来删除此元素,在删除之前,先将迭代器指向下一个元素。

      这样做有两个地方引起错误:

        1、当it指向元素8时,it.base()返回的迭代器指向it的前一个位置,即指向元素9;

        2、使用erase删除it.base()后,it的值未定义,即删除后,it的值不存在了,而不是原来++it的值。

      针对错误1,我们可以改使用(++it).base()来返回指向正确位置的迭代器。(请注意不要使用++it.base(),这样做修改返回值,是极不推荐的做法)。

      针对错误2,我们需要知道,erase函数的返回值就是 删除该元素后指向的下一个位置的迭代器。因此只要记录下erase的返回值,就能正确获得it的值。

      根据以上两点说法,将代码13-21行修改为

     1     for(it = l.rbegin();it != l.rend() && count;)
     2     {
     3         if(*it == 8 || *it == 5)
     4         {
     5             list<int>::iterator iter = l.erase((++it).base());// 记录删除该元素后的指向下一个位置的迭代器(注意删除8时,下一个是9)
     6             it = list<int>::reverse_iterator(iter);// 将该迭代器转换为reverse_iterator,此时it指向7
     7             -- count;
     8         }
     9         else
    10             ++it;
    11     }

      以上代码变可以成功删除容器中的5和8两个元素,并使容器中存储的为1,2,3,4,6,7,9.

      到此,仍有一个需要特别留意的问题:上面的第5行代码,删除8时,得出的iter指向的“下一个元素”是9,而不是7。而第六行执行完以后,it指向的是7

      其实这个应该挺好理解,但是在下水平有限,不太会解释。指出这一点是为了让大家多留个神,否则容易给自己挖了个坑。详细解释请查阅其他资料。以下为正确的完整代码写法:

    #include <iostream>
    #include <list>
    using namespace std;
    int main()
    {
        //MergeSortTest(); // 测试题目一,归并排序
        //movableWindowsTest();// 测试题目二,移动窗口,输出窗口中的最小值
        list<int> l;
        for(int i = 0;i < 10;++i)
            l.push_back(i);// 初始化容器存入0-9十个整数
        list<int>::reverse_iterator it;
        int count = 2;// 记录剩下需要删除元素的个数
        for(it = l.rbegin();it != l.rend() && count;)
        {
            if(*it == 8 || *it == 5)
            {
                list<int>::iterator iter = l.erase((++it).base());// 记录删除该元素后的指向下一个位置的迭代器(注意删除8时,下一个是9)
                it = list<int>::reverse_iterator(iter);// 将该迭代器转换为reverse_iterator,此时it指向7
                -- count;
            }
            else
                ++it;
        }
        for(list<int>::iterator iter = l.begin();iter != l.end();++iter)
            cout << *iter << " ";
        cout << endl;
        return 0;
    }
    View Code
  • 相关阅读:
    [bbk4999] 第100集 第12章 数据移植 06
    [bbk4992] 第98集 第12章 数据移植 04
    [bbk0000] 第101集 第12章 数据移植 08 本章案例 > 使用ORACLE_DATAPUMP擎创建外部表
    PL/SQL
    [zz]Python:time.clock() vs. time.time()
    MVC简介
    ajax_get/post_两级联动
    Ajax
    JAVAUML
    类与接口的区别
  • 原文地址:https://www.cnblogs.com/SunboyL/p/reverse_iterator_erase.html
Copyright © 2020-2023  润新知