反向迭代器reverse_iterator与正向迭代器iterator之间的转换(list反向删除元素的方法)

来源:互联网 发布:网络设备管理规范 编辑:程序博客网 时间:2024/06/05 10:46

首先,本文的公众号地址为:你真的会清理std::list的元素吗?

转载请注明出处,谢谢!

有经验的程序员都知道,list是链表,可以遍历删除,删除的过程类似于以下代码(遍历删除521):


int key=521;//程序员就不要爱情了吧list<int>::iterator it=l.begin();//l为std::list<int>    for (; it != l.end();)    {        if (key== *it) {            it = l.erase(it);        }        else {            ++it;        }    }



这是我们通常使用的删除方法,我们现在有一种场景:

公司为了惩罚员工迟到(我瞎说的,迟到了是要扣工资的。工作实际遇到的场景描述过于复杂),对于某一天的迟到的员工进行处罚,并且,由于有些员工是,年龄大了,网开一面,就不惩罚了。

假设我们的员工打开记录都存放在一个list里面,按照时间顺序存放,来的晚的打卡记录就在后面。



定义打卡的结构体:

struct DingDong{       long id;//员工id       long time;//打卡时间       int age;//员工年龄,人性化考虑,大于45岁的员工不处罚        };



信息定义:

typedef std::list<DingDong> DingDongList;DingDongList dd_list;///全部员工打开记录DingDongList punish_list;//惩罚员工名单long normal_time = 90000;//正常上班时间int normal_avg = 45;//惩罚的年龄上限,包含45岁




员工的打卡记录类似于:




场景描述完毕,我们开始处理


我们是个大厂子,有个10万的员工(我们不是鹅厂的,场景纯属虚构),

每天迟到的可能就100到200,从头开始遍历,很不明智,于是我们逆序遍历,并且,90000上班(9:00:00),大于45岁不处罚,代码如下


DingDongList::reverse_iterator r_iter = dd_list.rbegin();for (; r_iter != dd_list.rend();){if (r_iter->time <= normal_time) break;//迟到的员工都找到了if (r_iter->age<=45){punish_list.push_back(*r_iter);//删掉该节点}else{++r_iter;}}


//punish_list拿去惩罚吧,dd_list剩下的员工都是好同志(45岁以上迟到的老人也算是好同志)。


看到了“删除该节点"位置,该怎么删掉该节点呢。通过查询,我们发现list的erase()方法的参数只有如下几种,并没有对反向迭代器的删除操作:



那怎么办呢?难道就无法删除反向迭代器的元素了?

通过分析STL的iterator和reverse_iterator源码实现,发现了一些东西:

 





首先是,反向迭代器是继承迭代器的


反向迭代器的求值操作求的是 (*(--current)),即当前存储迭代器的前一个迭代器的值。


->操作则是求*操作后,求地址。


这些事实说明,reverse_iterator的求值和->操作都返回的是--iterator位置的数据。或者说,当前反向迭代器里面的指针指向的是,所访问的元素的下一个元素。





怎么把reverse_iterator转换成iterator呢?毕竟erase()能够删除的是iterator。

经过查证,发现了





那么,base()方法求到的是



实际上我们要删除的是元素5,那么求出指向5的正向迭代器呢?



分析代码我们知道,反向迭代器的++操作是指针往前挪动,即++rbegin()之后,reverse_iterator内部存储的指针就指向了元素5,然后求一下base()就是指向5的正向迭代器了(++rbegin()).base();





那么,逆序删除list元素的过程就呼之欲出了吧,放代码:


DingDongList::reverse_iterator r_iter = dd_list.rbegin();for (; r_iter != dd_list.rend();){if (r_iter->time <= normal_time) break;//迟到的员工都找到了if (r_iter->age <= 45){punish_list.push_back(*r_iter);r_iter = DingDongList::reverse_iterator(dd_list.erase((++r_iter).base()));}else{++r_iter;}}



到此,利用反向迭代器删除某些元素的功能就完成了。迟到的年轻员工,等着扣工资吧


本文提到的reverse_iterator的实在/usr/include/c++/4.4.7/bits/stl_iterator.h文件中当然,因为gcc版本的不同4.4.7这个路径可能是4.8.5或者4.8.2,有兴趣的话可以自己拿到源码分析一下,就一目了然了.