正反向迭代器关系及转换

反向迭代器reverse_iterator是一种反向遍历容器的迭代器,也就是从最后一个元素到第一个元素遍历容器。反向迭代器的自增(或自减)的含义反过来了:对于反向迭代器,++运算符将访问前一个元素,–运算符将访问下一个元素。 

    在某些场景下,reverse_iterator能很好地适应应用需求。但容器的有些成员方法只支持iterator,如果你想在反向迭代器所指的位置插入一个新元素,或者是删除反向迭代器所指的元素是不行的,因为insert方法、erase方法都不支持reverse_iterator。要完了这些操作,必须将reverse_iterator转换成iterator,再用iterator完成这些操作。 

    下面说明了反向迭代器与迭代器的关系,并列举了一些常用的操作。 

反向迭代器与迭代器的转换 

    reverse_iterator与iterator都继承自_Iterator_base,它们是可以相互转换的。 

  • 调用reverse_iterator的base()方法可以获取"对应的"iterator。 
  • 可以用iterator构造一个"对应的"reverse_iterator。 

   下面的两个例子展示了它们之间的转换: 

list<int> test_list; 
for (size_t i = 1; i < 8; i++) 

    test_list.push_back( i*2 ); 

list<int>::reverse_iterator rit = find(test_list.rbegin(), test_list.rend(), 8); 
list<int>::iterator it(rit.base()); 
cout << *rit << endl; 
cout << *it << endl;

 

   上面的代码是先查找到一个指向8的reverse_iterator,并reverse_iterator的base()方法得到一个iterator。但是从输出上看,iterator指向的元素的值并不是8,而是10。 

list<int> test_list; 
for (size_t i = 1; i < 8; i++) 

    test_list.push_back( i*2 ); 

list<int>::iterator it = find(test_list.begin(), test_list.end(), 8); 
list<int>::reverse_iterator rit(it); 
cout << *it << endl; 
cout << *rit << endl; 

   上面的代码是先查找一个指向8的iterator,然后用该iterator构造一个reverse_iterator。但是从输出上看,reverse_iterator指向的元素并不是8,而是6。 

   从上面这两个例子,我们看到reverse_iterator与iterator的这个"对应的"关系并不是一一对应的。那么反向迭代器与普通迭代器的关系到底是怎么样的呢? 

 

反向迭代器与迭代器的关系 

    下图清晰地显示了反向迭代器与迭代器之间的关系。 

 

    从上图可以看出,对于同一个容器: 

  • end()与rbegin()、begin()与rend()、rit与rit.base()并不是指向同一个位置。
  • 反向迭代器rit总是指向rit.base()的前一个位置。 
  • 反向迭代器标记的区间[rbegin(),rit)与迭代器标记的区间[rit.base(),end())是相同的。 

    为什么会这样呢?从技术上讲,把普通迭代器与反向迭代器间的关系设计成这样是为了适应容器是左闭右开的区间这个特性。《C++标准模板库》里是这么说的:"逆向迭代器的设计者运用了一个小技巧:他们实际上倒置了’半开原则’"。

 

反向迭代器的操作 

   了解了反向迭代器与迭代器的关系,再来对容器进行操作就很简单了。下面是常用操作的例子,例子中用的test_list的内容如上图所示: 

1. 遍历容器 

for(list<int>::reverse_iterator rit = test_list.rbegin(); rit != test_list.rend(); ++rit) 

    cout<< *rit << " "; 
} 

2. 插入元素 

    假设要在rit指向的位置插入一个新元素150,那么150应该在8和10之间。对于rit而言,150应该插入到rit的前一个位置。对于it (it = rit.base()),150应该插入it的前一个位置。 

所以,要实现在一个reverse_iterator rit指出的位置上插入新元素,在rit.base()指向的位置插入就行了。 

    操作代码如下: 

list<int>::reverse_iterator rit = find(test_list.rbegin(), test_list.rend(), 8); 
test_list.insert(rit.base(), 150); 

3. 删除元素 

    假设要删除rit指向的元素,就不直能删除rit.base()指向的元素了,rit指向的是8,而rit.base()指向的是10。实际上我们要删除的是rit.base()的前一个元素。 

所以,要实现在一个reverse_iterator rit指出的位置上删除元素,那么删除rit.base()的前一个元素就行了。 

操作代码如下: 

for(list<int>::reverse_iterator rit = test_list.rbegin(); rit != test_list.rend();) 

    if (8 == *rit) 
    { 
        list<int>::iterator it = --rit.base() ;  // 用(++rit).base()也可; 
        list<int>::iterator it_after_del = test_list.erase(it); 
        rit = list<int>::reverse_iterator(it_after_del); 
    } 
    else 
    { 
        ++rit; 
    } 
} 

    调用erase()删除元素后,返回值是指向被删除的元素的下一个元素的iterator,所以还需要把返回的iterator变成reverse_iterator赋值给rit。 

当然,上面的代码写成这样也是一个意思: 

for(list<int>::reverse_iterator rit = test_list.rbegin(); rit != test_list.rend();) 

    if (8 == *rit) 
    { 
        rit = list<int>::reverse_iterator(test_list.erase(--rit.base())); 
    } 
    else 
    { 
        ++rit; 
    } 
}

http://www.189works.com/article-40824-1.html
<think>好的,我现在需要解释反向迭代器(reverse iterator)在C++中的概念和用法。首先,反向迭代器是什么?它是STL中的一种迭代器适配器,允许我们逆向遍历容器。比如,从vector的末尾到开头,或者list的尾部到头部。 接下来,我需要说明它的基本用法。例如,使用rbegin()和rend()方法获取反向迭代器的起始和结束位置。然后,给出一个简单的代码示例,比如遍历vector并输出元素。这样用户可以看到具体的代码结构。 然后,解释实现原理。反向迭代器通过适配普通迭代器,重载操作符如operator++和operator--,使得递增操作实际上是递减底层迭代器。这里可能需要提到,当使用reverse_iterator的base()方法时,会返回对应的正向迭代器,但需要注意位置偏移的问题,比如rend().base()是begin(),而rbegin().base()是end()。 还要提到适用场景,比如需要逆序处理元素时,或者某些算法需要逆序操作的情况。同时,注意事项也很重要,例如在修改容器后反向迭代器可能失效,以及在插入或删除元素时需要考虑迭代器的有效性。 然后,给出一个更复杂的例子,比如在字符串中查找最后一个出现的某个字符,使用反向迭代器配合标准算法,如find,然后转换正向迭代器进行处理。这样的例子能帮助用户理解实际应用中的使用方法。 最后,总结反向迭代器的优点和需要注意的地方,比如简化逆序遍历代码,但使用时需注意迭代器失效和转换时的位置问题。 现在,我需要确保回答结构正确,先回答问题,再详细解释,然后给出相关问题。检查是否有遗漏的关键点,比如实现方式中的操作符重载,base()方法的使用注意事项,以及相关算法的例子是否恰当。确保代码示例正确,并符合C++标准,没有语法错误。同时,相关问题需要涵盖反向迭代器的基本概念、使用场景、与普通迭代器转换以及注意事项等方面。</think><< 反向迭代器(reverse iterator)是 C++ 标准库中提供的一种迭代器适配器,用于以逆序方式遍历容器。它通过反转底层容器的迭代方向实现,例如从容器末尾向开头移动。反向迭代器通过 `rbegin()` 和 `rend()` 方法获取。 ### 实现方式与核心特性 1. **基本用法** ```cpp #include <vector> #include <iostream> using namespace std; int main() { vector<int> vec = {1, 2, 3, 4, 5}; // 反向遍历输出 for (auto rit = vec.rbegin(); rit != vec.rend(); ++rit) { cout << *rit << " "; // 输出:5 4 3 2 1 } return 0; } ``` 2. **底层实现原理** 反向迭代器通过包装普通迭代器并重载运算符实现逆向移动: - `operator++` 实际调用底层迭代器的 `operator--` - `operator--` 实际调用底层迭代器的 `operator++` - `base()` 方法返回原始正向迭代器(需注意偏移问题) 3. **与正向迭代器转换** ```cpp auto rit = vec.rbegin(); // 反向迭代器起始位置(vec.end() - 1) auto original_it = rit.base(); // 对应正向迭代器为 vec.end() ``` ### 典型应用场景 - 逆序处理容器元素(如反向排序、逆序输出) - 查找最后一个满足条件的元素: ```cpp string s = "hello.world"; auto rit = find(s.rbegin(), s.rend(), '.'); // 查找最后一个'.' if (rit != s.rend()) { // 转换正向迭代器 auto pos = s.size() - (rit - s.rbegin()) - 1; cout << "Last '.' at index: " << pos; // 输出 5 } ``` ### 注意事项 1. **迭代器失效**:修改容器可能导致反向迭代器失效(与正向迭代器规则一致) 2. **边界问题**:`rend()` 对应容器的 `begin()` 前一个位置(哨兵位) 3. **性能**:反向迭代器操作的时间复杂度与底层迭代器相同
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值