首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

C++:使自定义类支持迭代器

编程知识
2024年09月10日 17:42

概述


在 C++ 中,链表迭代器是一种用来遍历链表(如 std::list)元素的工具。链表是一种数据结构,其中每个元素(节点)包含一个数据值和一个指向下一个节点的指针。链表迭代器允许以类似于数组的方式访问链表中的元素,但不需要直接操作指针。

链表迭代器的作用

  • 访问元素:链表迭代器使你能够顺序访问链表中的每个元素,就像在数组中遍历元素一样。

  • 遍历链表:通过迭代器,你可以在链表中前进或后退,从而进行遍历操作。这使得在链表中执行各种操作(如查找、修改、删除等)变得简单而直观。

  • 抽象化操作:迭代器提供了一种统一的方式来访问不同类型的数据结构。无论是链表、数组还是其他容器,迭代器的使用方式大致相同,这让代码更加通用和易于维护。

使用示例


#include <iostream>
#include <list>

int main() {
    std::list<int> myList = {1, 2, 3, 4, 5};
    
    // 使用迭代器遍历链表
    for (std::list<int>::iterator it = myList.begin(); it != myList.end(); ++it) {
        std::cout << *it << " ";  // 输出链表元素
    }
    
    return 0;
}

为什么要为自己的类设置迭代器?


参考下述链表类

class List {
public:
    List(): head(new Node()) { }
    ~List();

    bool push(int x, int y);    // 在头部插入一个新坐标
    bool pop(int x, int y);     // 查找指定坐标,并删除

private:
    Node* head;
};

在该链表中,定义了pushpop两个方法,现假定,我们需要能够从第一个节点开始,逐步在外部调用链表的每一个节点,有一种简单的实现方法:

  • 定义search(int i)函数,从头开始,向后查询i个节点
  • 在外部采用for循环递增节点索引i

这里给出一个伪代码:

for (int i = 0; i < 10; ++i) {
    Node cur = myList.search(i);
    std::cout << cur << std::endl;
}

上述方法能够实现在外部对链表节点的遍历,但是,当索引较大时,鉴于每一次都需要从头访问至索引处,算力开销极大,因此我们必须采用更高效的方法。

如何为类设置迭代器方法?


观察标准库中迭代器的使用方法:

for (std::list<int>::iterator it = myList.begin(); it != myList.end(); ++it) {
        std::cout << *it << " ";  // 输出链表元素
}

我们了解到需要实现如下内容:

  • 定义迭代器类,包含一个Node*类型的指针cur,指向当前元素。
  • 在链表类中,定义beginend函数,分别指向第一个元素和尾节点。
  • 定义!=运算符,以支持比较两个指针是否相同。
  • 定义++运算符,使得可以更便携的遍历节点。
  • 定义*运算符,使得可以采用指针方法访问到节点的值。

我们可以依次完成实现

class List {
public:
    List() : head(new Node()) { }
    ~List();

    bool push(int x, int y);
    bool pop(int x, int y);

    // 定义迭代器类
    class Iterator {
    public:
        // 构造函数
        Iterator(Node* node) : cur(node) {}
        // 指针运算符
        Cell& operator*() { return cur->cell; }
        // 前置自增运算符
        Iterator& operator++() {
            if (cur) cur = cur->next;
            return *this;
        }
        // 不等于运算符
        bool operator!=(const Iterator& other) const { return cur != other.cur; }

    private:
        // cur字段
        Node* cur;
    }

    // 分别定义begin()、end()方法
    Iterator begin() const { return Iterator(head->next); }
    Iterator end() const { return Iterator(nullptr); }

private:
    Node* head;
};

完成上述实现后,我们就可以使用迭代器方法快捷的访问类成员了。

#include <iostream>
#include "list.h"

int main() {
    List ROI;
    // 插入节点
    ROI.push(0, 0);
    ROI.push(0, 1);  
    ROI.push(0, 2);
    ROI.push(0, 3);

    for (List::Iterator it = ROI.begin(); it != ROI.end(); ++it) {
        std::cout << *it << "\n";
    }

    return 0;
}

为什么将迭代器类Iterator嵌入链表类List中?


  • 封装性:将Iterator类作为LinkedList的嵌套类,可以更好地封装链表内部的实现细节。这样Iterator类只能访问LinkedList类的私有成员,而其他类不能直接访问Iterator类的内部细节。

  • 逻辑关联Iterator是专门用于遍历LinkedList的,因此将它放在LinkedList类内部有助于保持逻辑上的一致性和相关性。这样可以清晰地表示Iterator是为LinkedList量身定做的。

  • 简化访问:嵌套类可以访问外部类的私有成员。对于Iterator来说,它需要访问LinkedList的内部节点,因此将它作为嵌套类可以简化访问逻辑,而不需要额外的接口或方法来暴露链表的内部结构。

From:https://www.cnblogs.com/SXWisON/p/18405181
本文地址: http://shuzixingkong.net/article/1921
0评论
提交 加载更多评论
其他文章 Activity启动模式
Activity启动模式 1. Activity启动模式介绍 1.1 任务栈 在Android开发中,任务栈(Task Stack)是一个非常重要的概念,主要用于管理应用程序中的Activity及其启动模式。它帮助开发者了解当用户在不同应用之间切换,或者应用内部不同Activity之间跳转时,系统如
Activity启动模式 Activity启动模式 Activity启动模式
剖析 Redis List 消息队列的三种消费线程模型
Redis 列表(List)是一种简单的字符串列表,它的底层实现是一个双向链表。 生产环境,很多公司都将 Redis 列表应用于轻量级消息队列 。这篇文章,我们聊聊如何使用 List 命令实现消息队列的功能以及剖析消费者线程模型&#160;。 1 核心流程 生产者使用&#160;LPUSH key
剖析 Redis List 消息队列的三种消费线程模型 剖析 Redis List 消息队列的三种消费线程模型 剖析 Redis List 消息队列的三种消费线程模型
.NET 多版本 WinForm 开源控件库 SunnyUI
前言 给大家推荐一款开源的 Winform 控件库,可以帮助我们开发更加美观、漂亮的 WinForm 界面。 项目介绍 SunnyUI.NET 是一个基于 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 开源控件库,同时也提供了工具类库、扩展
.NET 多版本 WinForm 开源控件库 SunnyUI .NET 多版本 WinForm 开源控件库 SunnyUI .NET 多版本 WinForm 开源控件库 SunnyUI
声明式 Shadow DOM:简化 Web 组件开发的新工具
在现代 Web 开发中,Web 组件已经成为创建模块化、可复用 UI 组件的标准工具。而 Shadow DOM 是 Web 组件技术的核心部分,它允许开发人员封装组件的内部结构和样式,避免组件的样式和行为影响全局页面。然而,传统的 Shadow DOM 实现方式需要通过 JavaScript 显式地
声明式 Shadow DOM:简化 Web 组件开发的新工具
RS485与ModbusRTU
前言 大家好!我是付工。 每次听到别人说RS485通信协议,就很想去纠正他。 今天跟大家聊聊关于RS485的那些事。 接口标准 首先明确一点,RS485不是通信协议,而是一种接口标准,它还有2个兄弟:RS232和RS422。 RS是Recommend Standard的缩写,对于串口通信,目前工业领
RS485与ModbusRTU RS485与ModbusRTU RS485与ModbusRTU
manim边学边做--常用多边形
多边形是常见的几何结构,它的形状看似千变万化,其实都可以由几种常用的多边形组合而成。 本篇介绍manim中提供的几个绘制常用多边形的模块。 Triangle:等边三角形 Square:正方形 Rectangle:长方形 RoundedRectangle:圆角的长方形 Star:没有相交线的正多边形,
manim边学边做--常用多边形 manim边学边做--常用多边形 manim边学边做--常用多边形
Qml 实现瀑布流布局
最近在刷掘金的时候看到一篇关于瀑布流布局的文章,然鹅他们的实现都是前端的那套,就想着 Qml 有没有类似实现。 结果百度了一圈也没有( T_T Qml 凉了凉了 ),于是,我按照自己理解,简单实现了一个 Qml 版的瀑布流布局。
Qml 实现瀑布流布局 Qml 实现瀑布流布局 Qml 实现瀑布流布局
Go runtime 调度器精讲(一):Go 程序初始化
原创文章,欢迎转载,转载请注明出处,谢谢。 0. 前言 本系列将介绍 Go runtime 调度器。要学好 Go 语言,runtime 运行时是绕不过去的,它相当于一层“操作系统”对我们的程序做“各种类型”的处理。其中,调度器作为运行时的核心,是必须要了解的内容。本系列会结合 Go plan9 汇编
Go runtime 调度器精讲(一):Go 程序初始化 Go runtime 调度器精讲(一):Go 程序初始化 Go runtime 调度器精讲(一):Go 程序初始化