C++ [STL容器反向迭代器]

这篇具有很好参考价值的文章主要介绍了C++ [STL容器反向迭代器]。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

C++ [STL容器反向迭代器]

本文已收录至《C++语言》专栏!
作者:ARMCSKGT

C++ [STL容器反向迭代器]


前言

我们知道STL大部分容器都有迭代器,迭代器又分为正向迭代器和反向迭代器,对于正向迭代器以及实现前面我们已经了解了不少,而反向迭代器的设计思想是适配器模式,本节我们介绍反向迭代器的实现!
C++ [STL容器反向迭代器]


正文

适配器


适配器是把一个类的接口变换成客户端所期待的另一种接口,从而使原本接口不匹配而无法在一起工作的两个类能够在一起工作!

那么到底什么是适配器?
C++ [STL容器反向迭代器]
我们常用的充电器就是一个例子,充电器也叫电源适配器,一个充电器可以充相同接口不同手机,这就是适配器!

适配器思想是利用已有的对象对其进行封装以满足我们的需要!


作为STL六大组件之一的适配器,一共有三类!

STL中有三类适配器

  • container adapters:容器适配器
    – 容器适配器底层套用其他容器作为底层容器,封装容器,改变容器的行为作为本容器适配器;容器适配器底层的容器可以修改,只要实现了容器适配器底层所需函数都可以作为容器适配器的底层容器;例如stack容器的底层是使用deque(双端队列),也可以修改为vector,在后面我们会着重介绍容器适配器

  • functor adapters:仿函数适配器
    – 如果说仿函数的设计是为了让必须有两个参数的普通函数能够被只能有传入一个参数的算法所使用的话,仿函数适配器则是为了让必须有两个参数的仿函数被算法调用;仿函数适配器非常厉害,几乎可以无限制的创造出各种可能的表达式

  • iterator adapters:迭代器适配器
    – 迭代器适配器主要是可以实现反向迭代器,反向迭代器独立实现与一个头文件,只要容器支持双向迭代器,都可以支持反向迭代器,反向迭代器是对正向迭代器的封装,改变其行为,满足条件的容器只需要声明反向迭代器的头文件便可以使用反向迭代器

C++ [STL容器反向迭代器]

图片出自《STL源码剖析》

反向迭代器


反向迭代器适用于所有的容器,因此它是作为一个单独的 .h 文件出现的,别的容器如果想使用,直接包含就行了!

反向迭代器 reverse_iterator 可以用来反向遍历容器,在某些场景下很实用!
C++ [STL容器反向迭代器]

图片出自《STL源码剖析》

反向迭代器框架

反向迭代器是对正向迭代器的封装,所以使用多模板参数!

模板参数:

  • Iterator:正向(普通)迭代器类型
  • Ref:迭代器下元素数据类型的引用类型
  • Ptr:迭代器下元素数据类型的指针类型


    之所以这样设计,也是为了简化代码,增强代码的复用性;对于 stringvectorlist,可以共用这一套代码就能同时实现反向迭代器。(对于其他容器,要么不支持迭代器或不支持双向迭代器,无法满足反向迭代器需求;又或之其容器迭代器底层实现复杂,需要单独实现,例如map和set)
    C++ [STL容器反向迭代器]

在迭代器对象中,我们需要一个成员变量保存当前的正向迭代器,所以定义一个普通迭代器变量 current 保存正向迭代器,方便操作!

反向迭代器在 ++ 和 - - 后需要返回一个反向迭代器,为了书写简单,我们将反向迭代器类型在类中typedef,定义为 self

template<class Iterator,class Ref,class Ptr>
struct Reverse_iterator
{
	Iterator current; //迭代器对象

	typedef Reverse_iterator<Iterator, Ref, Ptr> self; //反向迭代器类型
};

注意:反向迭代器思想与正向迭代器一样,只是用于封装,改变被封装对象的行为;所以在反向迭代器中的大部分操作都会调用正向迭代器中的函数进行操作!


默认成员函数

对于默认成员函数,我们只需要实现构造和拷贝构造即可!

	//Reverse_iterator() {} //默认构造
	explicit Reverse_iterator(Iterator x) //构造封装迭代器 - 禁止类型转换
		:current(x)
	{}

	Reverse_iterator(const self& x) //自对象(reserve_iterator)构造-拷贝构造
		:current(x.current)
	{}

因为是反向迭代器是对正向迭代器的封装,我们严格要求传入的参数必须是正向迭代器,禁止在构造时类型转换,防止出现以外!


反向迭代器的遍历

反向迭代器分别为 rbegin 和 rend ,rbegin 是对 end 的封装,rend 是对 begin 的封装!

//反向迭代器
//普通反向迭代器
reverse_iterator rbegin() { return reverse_iterator(end()); }
reverse_iterator rend() { return reverse_iterator(begin()); }
//const普通反向迭代器-应对特殊传参场景
const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
//const反向迭代器
const_reverse_iterator crbegin() const { return const_reverse_iterator(end()); }
const_reverse_iterator crend() const { return const_reverse_iterator(begin()); }

对于 vector<int> v = {1,2,3,4,5}; 遍历

  • 正向迭代器通过++遍历:1 2 3 4 5
  • 反向迭代器通过++遍历:5 4 3 2 1
    C++ [STL容器反向迭代器]

对于反向迭代器的遍历,从最后一个元素的下一个位置开始,反向迭代器的 ++ 就是对正向迭代器的 - -
因为我们封装的current就是正向迭代器,所以直接对current进行 ++ 或 - - 即可!

self& operator++()//前置++
{
	--current; //对于 ++ 先 -- 再返回迭代器
	return *this;
}

self operator++(int)//后置++
{
	self tmp(*this);
	--current;
	return tmp;
}

self& operator--() //前置--
{
	++current; //对于 -- 先 ++ 再返回对象
	return *this;
}

self operator--(int)//后置--
{
	self tmp(*this);
	++current;
	return tmp;
}

反向迭代器的比较

迭代器的比较,常用于遍历时的终止条件,即 == 和 != 比较!
对于这两种比较,直接调用正向迭代器的比较运算符即可!

// != 比较
bool operator!=(const self& n) const
{
	return current != n.current;
}
// == 比较
bool operator==(const self& n) const
{
	return current == n.current;
}
//直接调用正向迭代器的比较即可

反向迭代器数据访问

对于反向迭代器,我们也会使用 *-> 来访问数据,对于反向迭代器,访问数据就有所不同了!

前面我们提到,反向迭代器rbegin是封装end实现的,那么如果我们要访问反向遍历中的第一个元素,不能直接对反向迭代器中的正向迭代器调用 operator*()operator->() 否则就属于野指针访问了!

所以对于反向迭代器元素的访问,我们整体向前移动一位,即迭代器在end位置时,访问end-1位置的元素,这样既可以解决元素访问的问题,也可以解决了遍历时漏掉元素的问题!
C++ [STL容器反向迭代器]
如果不进行这样的设计,还会引发另一个问题:
C++ [STL容器反向迭代器]
如果按照我们想象的方式设计,遍历时第一个元素无法遍历到,因为当rbegin==rend时就退出了,于是设计者在设计时规定,迭代器访问元素时,默认访问迭代器位置的上一个位置元素,这样当迭代器处于2时,访问的就是1,这样就避免了这个问题且也不会出现rbegin越界访问问题!

// T&
Ref operator*() //解引用访问数据
{ //因为是反向迭代器,如果是begin访问则是end位置,此时需要先--再解引用
	Iterator tmp(current);
	--tmp;
	return *tmp;
}

// T*
Ptr operator->()
{
	Iterator tmp(current);
	--tmp;
	return &(operator*());
}

对于 operator->() 只需要复用 operator*() 对其返回值取地址即可!


反向迭代器代码

#pragma once
#include<iostream>
#include<assert.h>

template<class Iterator,class Ref,class Ptr>
struct Reverse_iterator
{
	Iterator current;

	typedef Reverse_iterator<Iterator, Ref, Ptr> self;

	//Reverse_iterator() {} //默认构造
	explicit Reverse_iterator(Iterator x) //构造封装迭代器 - 禁止类型转换
		:current(x)
	{}

	Reverse_iterator(const self& x) //自对象(reserve_iterator)构造-拷贝构造
		:current(x.current)
	{}

	//反向迭代器 ++ 相当于 --
	self& operator++()//前置++
	{
		--current;
		return *this;
	}
	//返回本对象
	self operator++(int)//后置++
	{
		self tmp(*this);
		--current;
		return tmp;
	}

	self& operator--() //前置--
	{
		++current;
		return *this;
	}

	self operator--(int)//后置--
	{
		self tmp(*this);
		++current;
		return tmp;
	}

	bool operator!=(const self& n) const
	{
		return current != n.current;
	}

	bool operator==(const self& n) const
	{
		return current == n.current;
	}

	//T&
	Ref operator*() //解引用访问数据
	{ //因为是反向迭代器,如果是begin访问则是end位置,此时需要先--再解引用
		Iterator tmp(current);
		--tmp;
		return *tmp;
	}

	Ptr operator->()
	{
		Iterator tmp(current);
		--tmp;
		return &(operator*());
	}
};

本节简单的介绍反向迭代器的思想,反向迭代器中还有一些功能,感兴趣的小伙伴可以研究研究!


测试反向迭代器

我们将反向迭代器植入我们自己实现的string,vector和list中进行实验!

list

void test()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	list<int> x(arr,arr+10);
	auto it = x.rbegin();
	while (it != x.rend())
	{
		cout << *(it) << " ";
		++it;
	}
}

C++ [STL容器反向迭代器]

vector

void test()
{
	int arr[] = { 448,558,668,778,888 };
	vector<int> x(arr, arr + 5);
	auto it = x.rbegin();
	while (it != x.rend())
	{
		cout << *(it) << " ";
		++it;
	}
	cout << endl << endl;
}

C++ [STL容器反向迭代器]

string

void test()
{
	string x("droW elloH");
	auto it = x.rbegin();
	while (it != x.rend())
	{
		cout << *(it) << " ";
		++it;
	}
	cout << endl << endl;
}

C++ [STL容器反向迭代器]

关于上面三个容器的测试代码如下:

  • string模拟实现
  • vector模拟实现
  • list模拟实现

代码仅简单实现,存在部分问题,敬请谅解!


最后

本节简单介绍了反向迭代器思想,将类和对象的封装意义体现的淋漓尽致,关于迭代器的介绍就告一段落,在后期,对于复杂容器,其迭代器的设计将会更加复杂,我们后面继续学习!

本次 <C++ STL容器反向迭代器> 就先介绍到这里啦,希望能够尽可能帮助到大家。

如果文章中有瑕疵,还请各位大佬细心点评和留言,我将立即修补错误,谢谢!
C++ [STL容器反向迭代器]

🌟其他文章阅读推荐🌟
C++ <STL之list模拟实现> -CSDN博客
C++ <STL之list使用> -CSDN博客
C++ <STL之vector模拟实现> -CSDN博客
C++ <STL之vector的使用> -CSDN博客
🌹欢迎读者多多浏览多多支持!🌹


文章来源地址https://www.toymoban.com/news/detail-500012.html

到了这里,关于C++ [STL容器反向迭代器]的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 深入探究C++中的STL:容器、迭代器与算法全解析

    Standard Template Library:标准模板库 是一个基于泛型的C++类模板库由Alexander Stepanov于1994年开发 其目的是为了提供一致通用和高效的数据结构和算法,同时不限制用户所处理的数据类型和编程范式。STL的原型最初由Andrew Koenig和其它C++专家小组进行设计并在1995年C++标准委员会的推

    2024年02月05日
    浏览(72)
  • 【C++】反向迭代器的模拟实现通用(可运用于vector,string,list等模拟容器)

    🌏博客主页: 主页 🔖系列专栏: C++ ❤️感谢大家点赞👍收藏⭐评论✍️ 😍期待与大家一起进步! 我们要写出一个通用的反向迭代器模拟而且在保证代码简介不繁琐的的情况下,一定程度上使用我们自己模拟的已经封装好的iterator迭代器可以简化许多步骤,首先我们要知

    2024年02月14日
    浏览(55)
  • 【STL】模拟实现反向迭代器

    目录 1. 读源码 2. 搭建框架  3. 迭代器的操作 operator*()  operator-() operator++() operator--() operator!=() 4. 实现 list 的反向迭代器 5. 实现 vector 的反向迭代器 6. 源码分享 写在最后: 我们之前实现的 vector,list 好像都只实现了他们的正向迭代器,那有正向, 会有反向迭代器这种东西吗

    2024年02月13日
    浏览(40)
  • 深入篇【C++】手搓模拟实现list类(详细剖析底层实现原理)&&模拟实现正反向迭代器【容器适配器模式】

    1.一个模板参数 在模拟实现list之前,我们要理解list中的迭代器是如何实现的。 在vector中迭代器可以看成一个指针,指向vector中的数据。它的解引用会访问到具体的数据本身,++会移动到下一个数据位置上去,这些都是因为vector具有天生的优势:空间上是连续的数组,这样指

    2024年02月15日
    浏览(45)
  • 【C++庖丁解牛】STL之vector容器的介绍及使用 | vector迭代器的使用 | vector空间增长问题

    🍁你好,我是 RO-BERRY 📗 致力于C、C++、数据结构、TCP/IP、数据库等等一系列知识 🎄感谢你的陪伴与支持 ,故事既有了开头,就要画上一个完美的句号,让我们一起加油 vector的文档介绍 vector是表示可变大小数组的序列容器。 就像数组一样,vector也采用的连续存储空间来存

    2024年03月14日
    浏览(79)
  • STL之list模拟实现(反向迭代器讲解以及迭代器失效)

    这次是关于list的模拟实现的代码,先看看下面的代码: 上面是list的代码,其底层是一个带头双向循环的链表,实现的方法就不说了,相信大家已经都会了,然后自己实心的list我没有写析构函数等,这个也很简单,循环利用成员函数中的删除函数就可以。 先来说说个人认为

    2024年02月11日
    浏览(41)
  • 【C++STL】list的反向迭代器

    list的反向迭代器 reverse.h list.h test.cpp 疑问1:为什么在迭代器当中不需要写深拷贝、析构函数 1、因为迭代器就是希望做到浅拷贝,就是需要拿到地址而不是值,因为迭代器的修改是会影响对象中的内容的 2、因为迭代器并没有申请额外的空间,所以不需要析构,如果写了析构

    2024年02月12日
    浏览(37)
  • 【STL】优先级队列&反向迭代器详解

    目录 一,栈_刷题必备 二,stack实现 1.什么是容器适配器 2.STL标准库中stack和queue的底层结构  了解补充:容器——deque  1. deque的缺陷 2. 为什么选择deque作为stack和queue的底层默认容器 三,queue实现 1. 普通queue  2,优先级队列(有难度) 1. 功能 2. 模拟实现 1). 利用迭代器_构造

    2024年02月13日
    浏览(39)
  • 【数据结构与算法】C++的STL模板(迭代器iterator、容器vector、队列queue、集合set、映射map)以及算法例题

    更多算法例题链接: 【数据结构与算法】递推法和递归法解题(递归递推算法典型例题) 什么是迭代器(iterator) 迭代器(iterator)的定义: 迭代器是一种检查容器内元素并遍历元素的数据类型。 迭代器提供对一个容器中的对象的访问方法,并且定义了容器中对象的范围。 容器

    2024年04月14日
    浏览(49)
  • 【C++_STL】优先级队列&反向迭代器详解

    目录 一,栈_刷题必备 二,stack实现 1.什么是容器适配器 2.STL标准库中stack和queue的底层结构  了解补充:容器——deque  1. deque的缺陷 2. 为什么选择deque作为stack和queue的底层默认容器 三,queue实现 1. 普通queue  2,优先级队列(有难度) 1. 功能 2. 模拟实现 1). 利用迭代器_构造

    2024年02月09日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包