您的位置:首页 > 编程语言 > C语言/C++

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

2017-07-05 23:01 459 查看

首先,本文的公众号地址为:你真的会清理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,有兴趣的话可以自己拿到源码分析一下,就一目了然了.



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息