<C++> 反向迭代器

本文详细介绍了STL中的反向迭代器构造方式,包括其与正向迭代器的关系,适配器模式的应用以及如何通过模板实现统一的反向迭代器。以list和vector为例,展示了如何在容器中使用rbegin和rend进行适配。

一、反向迭代器构造方式

1. 正向迭代器

        我们知道正向迭代器的设计:begin迭代器指向第一个数据,end迭代器指向最后一个数据的下一个位置 。

        迭代器++,移向下一个数据,解引用得到数据的值。

        根据容器储存方式的不同,容器有不同类型的迭代器。

2. 反向迭代器

        注意:rbegin迭代器指向最后一个数据的下一个位置,rend迭代器指向第一个数据,这里就体现了镜像对称,正向与反向迭代器成为对称关系。

        可是,如果按照rebegin指向的位置,第一次解引用得到的应该是随机值,这是有问题的,那么stl解决方案是什么呢?它采用的方法是:解引用得到的是rebegin迭代器前一个位置的数据

        为了简便,反向迭代器采用的是适配器模式,适配正向迭代器反向迭代器的++将调用正向迭代器的--,反之亦然。

例如:

二、反向迭代器模板 

         我们给出统一的反向迭代器模板,对于各容器,由模板实现各自的迭代器。给模板什么正向迭代器,它就适配出相应容器的反向迭代器

#pragma once
namespace my_ReverseIterator
{
	template<class Iterator, class Ref, class Ptr>
	struct ReverseIterator
	{
		typedef ReverseIterator<Iterator, Ref, Ptr> self;
		Iterator _it;

		ReverseIterator(Iterator it)
			:_it(it)
		{}

		Ref operator*()
		{
			Iterator tmp = _it;
			return *(--tmp);	//这里没有模板类型,该返回什么类型呢?1. 萃取 2. 使用者在模板处给出
		}

		Ptr operator->()
		{
			return &(operator*());

			//还可以写成
			//Iterator tmp = _it;
			//return &(*--tmp);
		}

		self& operator++()
		{
			--_it;
			return *this;
		}

		self& operator--()
		{
			++_it;
			return *this;
		}

		bool operator!=(const self& s) const
		{
			return _it != s._it;
		}
	};
}

成员变量

  • 反向迭代器采用适配器模式将iterator类型变量作为反向迭代器类的成员变量(同stack、queue、priotiry_queue的构造方法一样)
  • 后两个模板类型与Iterator模板类型相同,用于不同权限的返回值,
  • Ref:T& 或 const T& 
  • Ptr: T*  或 const T*
#pragma once

namespace my_ReverseIterator
{
	template<class Iterator, class Ref, class Ptr>
	struct ReverseIterator
	{
		typedef ReserveIterator<Iterator, Ref, Ptr> self;
        
        //成员变量
		Iterator _it;
	};
}

operator*

  • 根据STL的构造,返回--后迭代器指向的数据
  • *(--tmp)实际上是调用了iterator类内部的operator*()函数,返回迭代器指向的数据的值
		Ref operator*() 
		{
			Iterator tmp = _it;
			return *(--tmp);	//这里没有模板类型,该返回什么类型呢?1. 萃取 2. 使用者在模板处给出
		}

operator->

  •  同Iterator的operator->()设计思想,该函数是为了防止数据类型不是单一数据,可能是类或结构体,含有多数据时只有解引用是不够用的,是错误的
  • 可以返回 &(operator*())   也可返回 &(*--_tmp)&(*--_tmp)表示的是:--tmp后,先调用tmp的operator*()函数,得到数据的值(可能是结构体,即自定义类型,也可能是单一的数据,即内置类型),再取地址即可
		Ptr operator->()
		{
            //Iterator tmp = _it;
            //return &(*--tmp);
			return &(operator*());
		}

operator++ && operator--

  • 前置的++或-- 
  • 返回引用,是因为*this表示的是反向迭代器这个类实例化的对象,它的生命周期是不在该operator++或--类内部的,所以可以返回引用
		self& operator++()
		{
			--_it;
			return *this;
		}

		self& operator--()
		{
			++_it;
			return *this;
		}

operator!=

  • 反向迭代器的比较,比较低是成员变量iterator,比较iterator时,又会转换为iterator重载的operator!=函数
  • 形参const修饰反向迭代器,常引用权限,外部的const是修饰 *this,表示不可修改this指针里的内容
		bool operator!=(const self& s) const
		{
			return _it != s._it;
		}

三、补充之前模拟实现的容器反向迭代器设计

我们补充上list、vector容器的迭代器

1. list

要将ReverseIterator头文件展开在list模拟实现的文件中,并展开命名空间域,这样编译器才会识别ReverseIterator这个类型

		typedef __list_iterator<T, T&, T*> iterator;	//迭代器要公有,让外面可以使用
		typedef __list_iterator<T, const T&, const T*> const_iterator;
		typedef ReverseIterator<iterator, T&, T*> reverse_iterator;
		typedef ReverseIterator<const_iterator, const T&, const T*> const_reverse_iterator;

		//用 end 适配 rbegin
		reverse_iterator rbegin()
		{
			return reverse_iterator(end());
		}

		//用 begin 适配 rend
		reverse_iterator rend()
		{
			return reverse_iterator(begin());
		}

		iterator begin()
		{
			//由指针类型隐式转换为iterator类
			//return _head->_next;

			//也可以用匿名对象
			return iterator(_head->_next);
		}

		iterator end()
		{
			return iterator(_head);
		}

2. vector

		typedef T* iterator;
		typedef const T* const_iterator;
		//此时反向迭代器是自定义类型
		typedef ReverseIterator<iterator, T&, T*> reverse_iterator;
		typedef ReverseIterator<const_iterator, const T&, const T*> const_reverse_iterator;

		reverse_iterator rbegin()
		{
			return reverse_iterator(end());
		}

		reverse_iterator rend()
		{
			return reverse_iterator(begin());
		}

		iterator begin()
		{
			return _start;
		}

		iterator end()
		{
			return _finish;
		}

        其余容器也相同,读者可自行添加


总结:        

        反向迭代器也是适配器模式,这是重点,使用 end() 适配 rbegin(),begin() 适配 rend()。

        我们搞清楚,这些类之间的关系,简单的一个*或!=它的背后都可能是运算符重载,简单的=可能是调用默认生成的赋值运算符重载而实现的


        最后,如果小帅的本文哪里有错误,还请大家指出,请在评论区留言(ps:抱大佬的腿),新手创作,实属不易,如果满意,还请给个免费的赞,三连也不是不可以(流口水幻想)嘿!那我们下期再见喽,拜拜!

### C++ String 反向迭代器的使用方法 在 C++ 中,`std::string` 提供了反向迭代器的功能,允许从字符串末尾向遍历字符。以下是关于 `std::string` 的反向迭代器使用的详细介绍。 #### 创建和初始化反向迭代器 可以利用成员函数 `rbegin()` 和 `rend()` 来获取指向字符串最后一个有效字符位置以及理论上的一个位置之反向迭代器: ```cpp #include <iostream> #include <string> int main() { std::string str = "hello"; // 获取反向迭代器 auto rit = str.rbegin(); } ``` #### 遍历整个字符串 通过循环结构配合上述获得的反向迭代器对象实现对字符串内所有元素按逆序访问的效果: ```cpp for (; rit != str.rend(); ++rit) { std::cout << *rit; } // 输出 olleh ``` 这里需要注意的是,在比较终止条件时应采用不等于运算符(`!=`)而非小于号(`<`);另外每次迭代操作后记得更新当指针的位置即执行自增/自减动作以便移动到下一个目标处[^1]。 #### 查找特定子串并打印其后的部分 假设现在有一个需求是要找到某个指定模式第一次出现的地方之后的内容,则可借助标准库中的算法如 `std::search` 结合反向迭代来进行处理: ```cpp if (auto pos = std::search(str.rbegin(), str.rend(), std::boyer_moore_searcher( target_string.rbegin(), target_string.rend())); pos != str.rend()) { // 找到了匹配项 std::copy(pos.base(), str.end(), std::ostream_iterator<char>(std::cout)); } else { // 没有发现任何符合条件的结果 std::cout << "Not Found!"; } ``` 此段代码展示了当定位成功后如何继续输出剩余未被检索过的序列片段[^2]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值