第16课-C++ STL 学习之【双向迭代器】(正,反向迭代器)

一、前言

在 C++ 的标准模板库(STL)中,迭代器是一种非常重要的概念,它提供了一种统一的方式来访问容器中的元素。在上一篇文章中我们学习了反向迭代器,它允许我们反向遍历容器。除了反向迭代器外,还有双向迭代器,它结合了正向迭代器和反向迭代器的一些特性,能够在容器中进行双向遍历。本文将详细介绍双向迭代器的设计思想、实现方式以及在常见容器中的应用。

二、双向迭代器设计

(一)双向思想

双向迭代器的核心思想是能够在容器中进行双向移动。与正向迭代器只能向前移动(通过operator++)和反向迭代器只能向后移动(通过operator--)不同,双向迭代器既可以向前移动,也可以向后移动。这使得它在某些需要在容器中来回遍历的场景下非常实用。

例如对于一个存储整数的vector容器{1, 2, 3, 4, 5},使用正向迭代器遍历得到的结果是1 2 3 4 5,使用反向迭代器遍历得到的结果是5 4 3 2 1,而使用双向迭代器则可以根据需要灵活地在两个方向上进行遍历。

(二)多参数模板

在设计双向迭代器类时,为了处理不同类型的容器和元素,我们可以借鉴反向迭代器中多参数模板的思想。通过使用多参数模板,可以使双向迭代器类更加通用,能够适应各种不同的容器和元素类型。

例如,我们可以定义一个双向迭代器模板类如下:

template <class Iterator, class Ref, class Ptr>
struct __bidirectional_iterator
{typedef __bidirectional_iterator<Iterator, Ref, Ptr> self;Iterator _cur;__bidirectional_iterator(Iterator cur) : _cur(cur) {}
};

这里的Iterator表示底层的正向迭代器类型,Ref用于返回目标对象引用,Ptr用于返回目标对象指针。

(三)基本操作实现

向前移动操作(operator++
双向迭代器的向前移动操作与正向迭代器类似,但需要考虑到它可能是基于其他迭代器类型实现的。例如,如果是基于正向迭代器实现的双向迭代器,operator++操作可以直接调用底层正向迭代器的operator++操作。

self& operator++()
{++_cur;return *this;
}
self operator++(int)
{Iterator tmp = _cur;++_cur;return tmp;
}

向后移动操作(operator--
向后移动操作是双向迭代器的关键特性之一。它的实现方式与反向迭代器的operator--操作类似,即与正向迭代器的移动方向相反。

self& operator--()
{--_cur;return *this;
}
self operator--(int)
{Iterator tmp = _cur;--_cur;return tmp;
}

解引用操作(operator*
解引用操作用于获取迭代器当前所指向的元素。对于双向迭代器,解引用操作与正向迭代器的解引用操作基本相同,只是需要考虑到它可能是基于其他迭代器类型实现的。

Ref operator*()
{return *_cur;
}

成员访问操作(operator->
成员访问操作用于获取迭代器所指向元素的成员指针。它的实现方式与反向迭代器的operator->操作类似,即通过解引用操作获取元素指针。

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

比较操作(operator==operator!=
双向迭代器需要实现比较操作,以便能够判断两个迭代器是否指向相同的位置。比较操作的实现方式与反向迭代器类似,都是通过比较底层迭代器的位置来实现的。

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

三、应用于vector

vector容器中应用双向迭代器,首先需要在vector类中定义双向迭代器类型。

template <class T>
class vector
{
public://...//双向迭代器typedef __bidirectional_iterator<iterator, T&, T*> bidirectional_iterator;typedef __bidirectional_iterator<const_iterator, const T&, const T*> const_bidirectional_iterator;bidirectional_iterator begin() { return bidirectional_iterator(_start); }bidirectional_iterator end() { return bidirectional_iterator(_finish); }const_bidirectional_iterator begin() const { return const_bidirectional_iterator(_start); }const_bidirectional_iterator end() const { return const_bidirectional_iterator(_finish); }//...
private:iterator _start;iterator _finish;iterator _end_of_storage;
};

然后,可以使用双向迭代器对vector进行遍历。

void TestVectorWithBidirectionalIterator()
{vector<int> v = {1, 2, 3, 4, 5};vector<int>::bidirectional_iterator it = v.begin();while (it!= v.end()){cout << *it << " ";++it;}cout << endl;// 反向遍历vector<int>::bidirectional_iterator rit = v.end();while (rit!= v.begin()){--rit;cout << *rit << " ";}cout << endl;
}

四、应用于list

对于list容器,同样可以应用双向迭代器。首先在list类中定义双向迭代器类型。

template <class T>
class list
{
public://...//双向迭代器typedef __bidirectional_iterator<iterator, T&, T*> bidirectional_iterator;typedef __bidirectional_iterator<const_iterator, const T&, const T*> const_bidirectional_iterator;bidirectional_iterator begin() { return bidirectional_iterator(_head->next); }bidirectional_iterator end() { return bidirectional_iterator(_head); }const_bidirectional_iterator begin() const { return const_bidirectional_iterator(_head->next); }const_bidirectional_iterator end() const { return const_bidirectional_iterator(_head); }//...
private:// 头节点相关定义//...
};

然后使用双向迭代器对list进行遍历。

void TestListWithBidirectionalIterator()
{list<int> l;l.push_back(1);l.push_back(2);l.push_back(3);list<int>::bidirectional_iterator it = l.begin();while (it!= l.end()){cout << *it << " ";++it;}cout << endl;// 反向遍历list<int>::bidirectional_iterator rit = l.end();while (rit!= l.begin()){--rit;cout << *rit << " ";}cout << endl;
}

双向迭代器是 C++ STL 中的一种迭代器类型,它具有以下优点和缺点:

优点

  1. 双向遍历能力
    • 双向迭代器的核心优势在于它能够在容器中进行双向移动。这使得它在处理需要在容器中来回遍历的情况时非常方便。例如,在对一个容器进行查找操作时,如果从容器的一端开始查找没有找到目标元素,使用双向迭代器可以很容易地从另一端重新开始查找,而不需要重新创建迭代器或者使用复杂的逻辑来控制遍历方向。
    • 与只能单向遍历的迭代器(如正向迭代器只能向前,反向迭代器只能向后)相比,双向迭代器提供了更大的灵活性,能够更好地适应各种不同的算法和数据处理需求。
  2. 通用性和兼容性
    • 双向迭代器在设计上通常具有较高的通用性。它可以基于不同类型的底层迭代器进行实现,并且能够适应各种容器类型。例如,它可以在vectorlist等不同的容器中使用,只要这些容器提供了相应的底层迭代器支持。
    • 这种通用性使得双向迭代器能够与许多 STL 算法和函数很好地兼容。例如,很多 STL 算法都要求迭代器具有双向移动的能力,双向迭代器能够满足这些要求,从而可以方便地应用这些算法来处理容器中的元素。
  3. 代码简洁性和可读性
    • 在使用双向迭代器的代码中,由于它能够在一个迭代器对象上实现双向遍历,不需要像使用正向和反向迭代器那样分别使用不同的迭代器对象来实现双向遍历,因此可以使代码更加简洁。
    • 例如,在一个循环中既可以向前遍历容器又可以向后遍历容器,只需要通过改变迭代器的移动方向操作(++--)即可,这样的代码逻辑更加清晰,易于理解和维护。

缺点

  1. 性能开销
    • 与某些特定方向的迭代器(如正向迭代器在正向遍历vector时)相比,双向迭代器可能会带来一些性能开销。因为双向迭代器需要支持双向移动的功能,其内部实现可能会相对复杂一些,这可能会导致在某些情况下遍历速度稍慢。
    • 例如,在对一个大型vector进行连续的正向遍历时,如果使用双向迭代器,虽然它也能够正确地完成遍历,但由于其内部可能需要处理双向移动的逻辑,可能会比使用专门的正向迭代器稍微慢一些。
  2. 功能局限性
    • 尽管双向迭代器能够双向遍历容器,但它的功能仍然相对有限。它不像随机迭代器那样能够直接访问容器中的任意位置(在常数时间内)。如果需要频繁地随机访问容器中的元素,双向迭代器可能不是最佳选择。
    • 例如,在一个需要快速定位到容器中某个特定位置元素的算法中,双向迭代器可能无法提供足够高效的访问方式,可能需要额外的操作来实现定位,这会增加算法的复杂性和时间开销。

五、总结

双向迭代器是 C++ STL 中一种非常实用的迭代器类型,它结合了正向迭代器和反向迭代器的优点,能够在容器中进行双向遍历。通过合理地设计双向迭代器类,并在常见容器中应用它,可以提高代码的灵活性和通用性。在实际编程中,根据具体的需求选择合适的迭代器类型对于提高程序的效率和可读性非常重要。希望通过本文的介绍,读者能够对双向迭代器有更深入的理解和掌握。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/55237.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Hi3061M开发板——系统时钟频率

这里写目录标题 前言MCU时钟介绍PLLCRG_ConfigPLL时钟配置另附完整系统时钟结构图 前言 Hi3061M使用过程中&#xff0c;AD和APT输出&#xff0c;都需要考虑到时钟频率&#xff0c;特别是APT&#xff0c;关系到PWM的输出频率。于是就研究了下相关的时钟。 MCU时钟介绍 MCU共有…

认识Java的异常

异常机制 异常机制指的是程序出现错误时&#xff0c;程序的处理方式。 程序的错误分为三种&#xff1a; 编译错误&#xff1a;由于没有遵循对于语言的语法规则&#xff0c;编辑器可以自动发现并提示的错误位置和原因。逻辑错误&#xff1a;程序没有按照预期的顺序执行。运行…

FreeRTOS应用开发学习

了解FreeRTOS 任务相关API FreeRTOS任务创建API FreeRTOS 中&#xff0c;任务的创建有两种方法&#xff0c;一种是使用动态创建&#xff0c;一种是使用静态创建。动态创建时&#xff0c;任务控制块和栈的内存是创建任务时动态分配的&#xff0c;任务删除时&#xff0c;内存可…

微信开发者工具提示获取手机号失败,客户端短信认证

长时间没有使用快捷登录方式&#xff0c;手机号授权过期&#xff0c; 如何解决 打开 开发者工具中&#xff0c;预览模式&#xff0c;在手机中完成&#xff0c;使用快捷登录&#xff0c;获取完整的手机号流程&#xff1b;验短流程完成后在开发工具也能获取到完整手机号了 Tar…

Mac电脑使用pyenv管理多版本python环境 _

利用Mac包管理工具brew安装pyenv&#xff0c;pyenv用来管理所有python版本。如果没有安装brew&#xff0c;先安装一下吧。 安装pyevn $ brew install pyenv $ pyenv -v pyenv 1.2.6查看所有的python版本&#xff08;pyenv管理的所有版本&#xff09; $ pyenv versions * sys…

TOML 格式配置文件:简洁与强大的选择

在软件开发中&#xff0c;配置文件是不可或缺的一部分。它们用于存储应用程序的设置、参数和其他重要信息。不同的配置文件格式各有特点&#xff0c;本文将介绍 TOML 格式配置文件&#xff0c;并与 YAML 格式进行对比&#xff0c;探讨其优劣。 一、TOML 格式介绍 TOML&#x…

LSTM和GRU

LSTM&#xff08;Long Short-Term Memory&#xff09;和GRU&#xff08;Gated Recurrent Unit&#xff09;都是循环神经网络&#xff08;Recurrent Neural Networks&#xff0c;RNNs&#xff09;的变体&#xff0c;专门设计用来解决传统RNN在处理长序列数据时遇到的梯度消失或梯…

C#里使用PerformLayout,强制控件将布局逻辑应用于其所有子控件。

前几天&#xff0c;使用DataGridView来进行动态数据显示&#xff0c;但是发现左边的滚动条会显示不正确。 比如设置显示第100行了&#xff0c;但是滚动条的位置还是在最顶端&#xff0c; 如果你去点击一下滚动条&#xff0c;它又立即更新&#xff0c;并且跳到正确的位置显示。 …

申请商家转账到零钱功能所需材料及必过攻略

商家转账到零钱功能的快速开通方法&#xff0c;可以归纳为以下几个步骤&#xff1a; 一、确认商户资格与账号状态 1. 商户类型&#xff1a;该功能通常只对公司性质的商户开放&#xff0c;个体工商户及小微商户暂时无法申请。商家需为微信支付认证用户。 2. 账号状态&#xff…

网络层及ip报头

★★★★★默写&#xff1a; A类&#xff1a;0~127 B类&#xff1a;128~191 C类&#xff1a;192~223 A类私网&#xff1a;10.0.0 - 10.255.255.255 B类私网&#xff1a;172.16.0.0 - 172.31.255.255 C类私网&#xff1a;19.168.0.0 - 192.168.255.255 特殊&#xff1a; 0.0.0…

Windows远程桌面到Ubuntu

在Ubuntu系统中&#xff0c;默认情况下root账户是被禁用的&#xff0c;为了安全起见&#xff0c;建议不要直接使用root账户登录图形界面。但是&#xff0c;如果出于特定的管理或维护需求&#xff0c;您可以按照以下步骤启用和使用root账户登录图形界面&#xff1a; 启用root账户…

新手爬虫DAY1

这个错误信息表明在你的Python程序中&#xff0c;re.search() 函数没有找到预期的匹配项&#xff0c;因此返回了 None。当你尝试在 None 对象上调用 group(1) 方法时&#xff0c;Python 抛出了一个 AttributeError。 具体来说&#xff0c;错误发生在 pc.py 文件的第6行&#x…

AI大模型与相对论的结合点的思考、应用及相对论原理与公式表达

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下AI大模型与相对论的结合点的思考、应用及相对论原理与公式表达。在阐述相对论原理的基础上&#xff0c;通过数学复杂公式&#xff0c;分析了人工智能大模型在相对论领域的应用前景。文章深入挖掘了两大领域之间的联…

浏览器哪个好,占用cpu低。。电脑卡。流氓软件。。。火狐浏览器的使用。

用360安全浏览器打开b站&#xff0c;有时候占用CPU会升高&#xff0c;高达90%以上。一关闭b站就回落。 用谷歌浏览器打开b站&#xff0c;有时候占用CPU会升高&#xff0c;高达60%、70%&#xff0c;比360安全浏览器低一些。。一关闭b站就回落。 360安全浏览器、QQ浏览器&#xf…

厨房老鼠数据集:掀起餐饮卫生监测的科技浪潮

厨房老鼠数据集&#xff1a;掀起餐饮卫生监测的科技浪潮 摘要&#xff1a;本文深入探讨了厨房老鼠数据集在餐饮行业卫生管理中的重要性及其相关技术应用。厨房老鼠数据集通过收集夜间厨房图像、老鼠标注信息以及环境数据&#xff0c;为深度学习模型提供了丰富的训练样本。基于…

MongoDB 安装配置及配置和启动服务

MongoDB 安装配置 附&#xff1a;MongoDB官网下载地址&#xff1a; https://www.mongodb.com/download-center/community 注&#xff1a; 官网可以下载最新版的MongoDB安装包&#xff0c;有MSI安装版和ZIP安装版。我们课堂上使用4.4.4的ZIP安装版。安装版参考博客&#xff1…

Spark第一天

MapReduce过程复习 Spark由五部分组成 RDD五大特征 1、 Spark -- 代替MapReduce <<<<< scala是单机的&#xff0c;spark是分布式的。>>>>> 开源的分布式计算引擎 可以快速做计算 -- 因为可以利用内存来做一些计算 (1) 分为5个库(模块) : 1、…

安装指定node.js 版本 精简版流程

首先 我们本机上是否安装有node 如果有 需要先卸载 卸载完成后 使用命令查看是否卸载干净 打开WinR 输入cmd 然后输入如下名: where node 如果没有目录显示 说明node 很干净 本机没有相关安装 在输入命令: where npm 如果有相关目录 需要删除掉 要不然 后续安装的…

报错 - LangChain bind_tools NotImplementedError

使用 LangChain 的 bind_tools 方法一直报错&#xff0c;即使使用 ChatOpenAI 作为 llm 接口 根据这个issue 下的回答&#xff0c;修改了 ChatOpenAI 的 import 出处&#xff0c;解决了问题 https://github.com/langchain-ai/langchain/issues/21479#issuecomment-2105618237 …

基于华为昇腾910B,实战 InternLM2.5-7B-Chat 模型推理

本文将带领大家基于启智平台&#xff0c;使用 LMDeploy 推理框架在华为昇腾 910B 上实现 internlm2_5-7b-chat 模型的推理。 GitHub - InternLM/lmdeploy: LMDeploy is a toolkit for compressing, deploying, and serving LLMs.&#xff08;欢迎star&#xff09; GitHub - I…