初识迭代器(Iterator)——迭代器模式——迭代加深(后续更新...)

news2024/11/23 19:56:44
学习网页:

Welcome to Python.orgicon-default.png?t=N7T8https://www.python.org/

迭代器(Iterator)

迭代器是一个非常有用的Python特性,它允许我们遍历一个容器(如列表、元组、字典、集合等)的元素。迭代器提供了一种方法,可以逐个访问这些元素,而不需要一次性加载所有元素到内存中。

迭代器实现了两个关键的方法:__iter__() 和 __next__()

  • __iter__() 方法返回迭代器对象本身。
  • __next__() 方法返回容器的下一个值。当容器中没有更多元素时,它将引发 StopIteration 异常。

这是一个简单的迭代器示例,该迭代器产生从0到给定数字的平方:

class Squares:  
    def __init__(self, max):  
        self.max = max  
        self.n = 0  
  
    def __iter__(self):  
        return self  
  
    def __next__(self):  
        if self.n < self.max:  
            result = self.n ** 2  
            self.n += 1  
            return result  
        else:  
            raise StopIteration  
  
# 使用这个迭代器  
squares = Squares(5)  
print(list(squares))  # 输出: [0, 1, 4, 9, 16]


在上面的例子中,__iter__() 方法返回迭代器对象本身,而 __next__() 方法则负责生成下一个平方数。当所有的平方数都被生成后,__next__() 方法引发一个 StopIteration 异常,表示迭代已经结束。

在Python中,你可以使用 for 循环来使用迭代器。当你使用 for 循环遍历一个容器时,Python会自动为这个容器创建一个迭代器,并使用 __next__() 方法逐个访问容器的元素。当 __next__() 方法引发 StopIteration 异常时,for 循环自动停止。

总而言之,

迭代器是一个强大的工具,它使得我们能够遍历各种数据结构,如列表、元组、字典、集合等,而无需一次性将所有元素加载到内存中。通过使用迭代器,我们可以逐个访问元素,而不是一次性加载所有元素。

在Python中,迭代器实现了两个关键的方法:__iter__() 和 __next__()__iter__() 方法返回迭代器对象本身,而 __next__() 方法则负责返回容器的下一个值。当容器中没有更多元素时,__next__() 方法将引发 StopIteration 异常,表示迭代已经结束。

我们可以自定义迭代器类来满足特定的需求。例如,上面的示例展示了一个名为 Squares 的迭代器类,它生成从0到给定数字的平方。我们可以使用 for 循环来使用这个迭代器,Python会自动调用 __next__() 方法来逐个访问平方数。当所有的平方数都被访问后,__next__() 方法引发 StopIteration 异常,for 循环自动停止。

使用迭代器可以节省内存空间,因为它允许我们逐个访问元素,而不是一次性加载所有元素。此外,迭代器还提供了更灵活的遍历方式,我们可以使用 while 循环和手动调用 __next__() 方法来遍历容器。

迭代器模式

迭代器模式是一种行为型设计模式,它提供了一种方法顺序访问一个聚合对象中的各种元素,而又不暴露该对象的内部表示。

在迭代器模式中,主要有以下几个参与者:

  1. Iterator(迭代器):迭代器定义访问和遍历元素的接口。
  2. ConcreteIterator(具体迭代器):具体迭代器实现迭代器接口,对该聚合遍历时跟踪当前位置。
  3. Aggregate(聚合):聚合定义创建相应迭代器对象的接口。
  4. ConcreteAggregate(具体聚合):具体聚合实现聚合接口,定义了创建相应迭代器对象的接口。
迭代器模式的主要优点包括:
  1. 简单性:通过使用迭代器,我们可以更简单地遍历容器中的元素,而无需了解容器的内部实现。
  2. 封装性:迭代器模式将对象的内部结构和遍历的过程都封装在迭代器中了,增加了系统的稳定性和可维护性。
  3. 抽象性:通过使用迭代器,我们可以抽象地处理不同类型的容器,而无需关心具体的容器实现。

然而,迭代器模式也有一些缺点

  1. 增加了系统的复杂性:使用迭代器模式需要额外的代码来实现迭代器和聚合类,增加了系统的复杂性。
  2. 性能问题:使用迭代器模式可能会比直接使用循环语句更慢,因为需要调用额外的函数和方法。
  3. 内存开销:由于需要创建额外的迭代器和聚合对象,因此可能会增加内存开销。

总之,迭代器模式是一种非常有用的设计模式,它提供了一种简单、封装性和抽象性的方法来遍历容器中的元素。但是,在使用时需要注意其缺点和限制。

迭代器模式是一种行为型设计模式,它提供了一种方法顺序访问一个聚合对象中的各种元素,而又不暴露该对象的内部表示。

”举个Java栗子“

以下是一个使用迭代器模式的简单例子(Java)

假设我们有一个班级,班级中有多个学生。我们想要遍历班级中的所有学生,并打印每个学生的姓名。

首先,我们定义一个迭代器接口:

public interface StudentIterator { 
boolean hasNext(); 
String next(); 
}

然后,我们定义一个班级类,该类实现了迭代器接口:


	public class Classroom implements StudentIterator { 

	private List<String> students; 

	private int currentIndex; 

	


	public Classroom(List<String> students) { 

	this.students = students; 

	this.currentIndex = 0; 

	} 

	


	@Override 

	public boolean hasNext() { 

	return currentIndex < students.size(); 

	} 

	


	@Override 

	public String next() { 

	if (hasNext()) { 

	return students.get(currentIndex++); 

	} else { 

	throw new NoSuchElementException("No more students in the class."); 

	} 

	} 

	}
现在,我们可以使用迭代器来遍历班级中的所有学生:
List<String> students = Arrays.asList("Alice", "Bob", "Charlie"); 
Classroom classroom = new Classroom(students); 
while (classroom.hasNext()) { 
System.out.println(classroom.next()); 
}

输出结果为:

Alice
Bob
Charlie

在这个例子中,我们定义了一个班级类,该类实现了迭代器接口。在迭代器接口中,我们定义了hasNext()next()方法,用于判断是否还有下一个元素和获取下一个元素。在班级类中,我们实现了这两个方法,并使用一个列表来存储学生姓名。然后,我们使用一个while循环来遍历班级中的所有学生,并打印每个学生的姓名。

”举个Python栗子“
class TreeNode:  
    def __init__(self, value):  
        self.value = value  
        self.children = []  
  
class TreeIterator:  
    def __init__(self, root):  
        self.stack = [root]  
  
    def hasNext(self):  
        return len(self.stack) > 0  
  
    def next(self):  
        node = self.stack.pop()  
        if node.children:  
            self.stack.extend(node.children[::-1])  
        return node.value  
  
# 创建一棵树  
root = TreeNode(1)  
child1 = TreeNode(2)  
child2 = TreeNode(3)  
child3 = TreeNode(4)  
root.children = [child1, child2]  
child1.children = [child3]  
  
# 创建迭代器对象  
iterator = TreeIterator(root)  
  
# 遍历树并打印每个节点的值  
while iterator.hasNext():  
    print(iterator.next())

输出结果为:

1
2
4
3

在这个例子中,我们定义了一个TreeNode类来表示树的节点,每个节点有一个值和一个子节点列表。然后我们定义了一个TreeIterator类来实现迭代器模式,它使用一个栈来存储要遍历的节点。在hasNext()方法中,我们检查栈是否为空;在next()方法中,我们从栈中弹出一个节点,并将其子节点(如果有的话)加入栈中。最后,我们使用一个while循环来遍历树并打印每个节点的值。

总结

在迭代器模式中,通过使用迭代器,我们可以更简单地遍历容器中的元素,而无需了解容器的内部实现。此外,迭代器模式还增加了系统的稳定性和可维护性,因为将容器的内部结构和遍历的过程都封装在迭代器中了。

使用迭代器模式可以抽象地处理不同类型的容器,而无需关心具体的容器实现。例如,我们可以编写一个通用的程序来遍历任何支持迭代器的容器,而无需了解容器的具体实现细节。

迭代加深

迭代加深是一种优化深度优先搜索(DFS)的方法。在深度优先搜索中,如果存在一个搜索树,树的深度很大,但答案却在深度很浅的右半部分子树中,DFS会搜索很多无用的节点。

迭代加深通过以下步骤来优化DFS:

  1. 在搜索深度限制为d时,重复搜索第1~d-1层的节点。
  2. 如果在第d-1层搜索失败了,扩大一层后,到了第d层,但我们还是得从第1层开始搜索。
  3. 重复这个过程,直到找到答案。

这种方法在搜索树的规模随着层次的深入增长很快,并且我们能够确保答案在一个较浅的节点时,可以有效地减少搜索的时间和空间复杂度。

好的,以下是一个使用迭代加深优化深度优先搜索的例子

假设我们有一个二叉树,树中的每个节点都有一个值。我们的目标是找到一个节点,使得该节点的值大于其子节点的值之和。

我们可以使用深度优先搜索来找到这个节点。但是,如果我们直接进行深度优先搜索,可能会搜索很多无用的节点,因为答案可能存在于深度很浅的节点中。

使用迭代加深可以优化这个搜索过程。我们可以从根节点开始进行深度为1的搜索。如果搜索失败,我们增加搜索的深度,直到达到一个预定的最大深度。在每次增加深度时,我们都会从最浅的层开始重新搜索,以避免重复搜索已经访问过的节点。

例如,假设我们有一个如下的二叉树:(markdown)

1  
/  \  
2    3  
/  \  
4    5

我们可以使用迭代加深来找到一个节点,使得该节点的值大于其子节点的值之和。首先,我们从根节点1开始进行深度为1的搜索。如果搜索失败,我们增加搜索的深度,直到达到最大深度3。在每次增加深度时,我们都会从最浅的层开始重新搜索。

在第一次搜索时,我们选择左子节点2作为当前节点。然后,我们检查2的右子节点是否存在,如果存在,我们继续搜索右子树;如果不存在,我们回到上一层并选择3作为当前节点。重复这个过程,直到找到答案或者达到最大深度。

在上述例子中,答案是3的父节点2,因为2的值大于其子节点2和3的值之和。使用迭代加深可以有效地减少搜索的时间和空间复杂度,避免在无用的节点上浪费时间和空间。

总结

在迭代加深中,我们首先从根节点开始进行深度为1的搜索。如果搜索失败,我们增加搜索的深度,直到达到一个预定的最大深度。在每次增加深度时,我们都会从最浅的层开始重新搜索,以避免重复搜索已经访问过的节点。

这种方法的主要优点是它可以有效地减少搜索的时间和空间复杂度。在深度很大的搜索树中,如果我们直接进行深度优先搜索,可能会浪费很多时间和空间。而迭代加深通过逐步增加搜索的深度来寻找答案,可以避免在无用的节点上浪费时间和空间。

此外,迭代加深还可以与其他优化技术结合使用,如剪枝、启发式搜索等,进一步提高搜索的效率。

需要注意的是,迭代加深并不适用于所有情况。如果搜索树的大小随着深度的增加而迅速增长,或者答案可能存在于深度很大的节点中,那么直接进行深度优先搜索可能会更有效。因此,在使用迭代加深之前,需要评估其适用性和效果。

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

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

相关文章

02什么是CPU上下文切换

上⼀节&#xff0c; 讲了要怎么理解平均负载&#xff08; Load Average&#xff09; &#xff0c; 并⽤三个案例展示了不同场景下平均负载升⾼的分析⽅法。 这其中&#xff0c; 多个进程竞争 CPU 就是⼀个经常被我们忽视的问题。 1、CPU上下文切换的概念 我想你⼀定很好奇&am…

软件开发人员,参加各种行业技术大会有意义么?

参加行业技术大会对于软件开发人员来说&#xff0c;是一个获取新知识、拓展视野、结交同行的宝贵机会。 1、知识更新&#xff1a;技术大会通常涵盖最新的技术趋势和工具。对于软件开发人员来说&#xff0c;这是了解新技术并将其应用到日常工作中的好机会。 2、拓宽视野&#x…

遥测终端机RTU如何选型和配置?

随着物联网技术的不断发展&#xff0c;遥测终端机RTU在各个领域的应用越来越广泛。RTU作为数据采集、传输和处理的核心设备&#xff0c;对于确保数据的准确性和稳定性至关重要。那么&#xff0c;如何选型与配置遥测终端机RTU呢&#xff1f;本文将为您揭秘RTU的选型与配置技巧&a…

【ros2 control 机器人驱动开发】简单双关节机器人学习-example 1

【ros2 control 机器人驱动开发】简单双关节机器人学习-example 1 文章目录 前言一、RR机器人创建description pkg创建demos pkg 二、创建controller相关创建example pkg 三、测试运行总结 前言 本系列文件主要有以下目标和内容&#xff1a; 为系统、传感器和执行器创建 Har…

HTML中边框样式、内外边距、盒子模型尺寸计算(附代码图文示例)【详解】

Hi i,m JinXiang ⭐ 前言 ⭐ 本篇文章主要介绍HTML中边框样式、内外边距、盒子模型尺寸计算以及部分理论知识 &#x1f349;欢迎点赞 &#x1f44d; 收藏 ⭐留言评论 &#x1f4dd;私信必回哟&#x1f601; &#x1f349;博主收将持续更新学习记录获&#xff0c;友友们有任何问…

简单描述从输入网址到页面显示的过程

当用户输入网址并按下回车键后&#xff0c;浏览器会进行以下步骤&#xff1a; DNS 解析&#xff1a;浏览器会解析网址中的域名部分&#xff0c;提取出需要访问的目标域名。然后&#xff0c;它会向本地 DNS 服务器发送一个 DNS 查询请求&#xff0c;以获取该域名对应的 IP 地址。…

Trie 字典树(c++)(前缀)

题目链接&#xff1a;用户登录 题目&#xff1a; 样例&#xff1a; 输入 5 3 aaa aba aabbaa abbbbb cdd aabba abc abab 输出 Y N N 思路&#xff1a; 根据题目意思&#xff0c;要用到 Trie 字典树算法。 Trie 字典树&#xff0c;顾名思义&#xff0c;“字典”&#xff0…

竞赛保研 wifi指纹室内定位系统

简介 今天来介绍一下室内定位相关的原理以及实现方法; WIFI全称WirelessFidelity&#xff0c;在中文里又称作“行动热点”&#xff0c;是Wi-Fi联盟制造商的商标做为产品的品牌认证&#xff0c;是一个创建于IEEE 802.11标准的无线局域网技术。基于两套系统的密切相关&#xff…

大四复习:深入浅出解释拓扑排序

我在大二学习拓扑排序的时候&#xff0c;不是很明白&#xff0c;现在已经大四&#xff0c;抽时间复习一下拓扑排序。 什么是拓扑排序&#xff1f; 如何实现拓扑排序&#xff1f; 拓扑排序的拓展 什么是拓扑排序&#xff1f; 首先拓扑排序的定义如下&#xff1a; 拓扑排序是一…

【C语言】SCU安全项目1-FindKeys

目录 前言 命令行参数 16进制转字符串 extract_message1 process_keys12 extract_message2 main process_keys34 前言 因为这个学期基本都在搞CTF的web方向&#xff0c;C语言不免荒废。所幸还会一点指针相关的知识&#xff0c;故第一个安全项目做的挺顺利的&#xff0c…

龙芯loongarch64服务器编译安装gcc-8.3.0

前言 当前电脑的gcc版本为8.3.0,但是在编译其他依赖包的时候,出现各种奇怪的问题,会莫名其妙的中断编译。本地文章讲解如何自编译安装gcc,替换系统自带的gcc。 环境准备 下载页面:龙芯开源社区网站 - LoongArch GCC 8.3 交叉工具链 - 源码下载源码包名称如:loongson-gnu…

修改antd表单Form.Item的label颜色的方法

默认的Form.item的标签颜色为黑色&#xff0c;但是如果我是用深色背景&#xff0c;这样的情况下表单就看不清楚label了&#xff0c;就像下面的情况&#xff0c;密码两个字完全看不到&#xff0c;所以想把它改为白色字体&#xff0c;就像上面的账号两个字一样&#xff1a; 所以怎…

黑马点评05分布式锁 1互斥锁和过期时间

实战篇-09.分布式锁-基本原理和不同实现方式对比_哔哩哔哩_bilibili 1.分布式锁 因为jvm内部的sychonized锁无法在不同jvm之间共享锁监视器&#xff0c;所以需要一个jvm外部的锁来共享。 2.redis setnx互斥锁 加锁解锁即可 2.1不释放锁可能死锁 redis 的setnx不会自动释放锁…

C语言是否已经跟不上社会需求?

今日话题。C语言是否已经跟不上社会需求&#xff1f;一个问题的提出者说&#xff0c;几天前他受到老板的批评&#xff0c;因为他只精通C语言编程&#xff0c;无法满足老板的需求。实际上&#xff0c;C语言在嵌入式行业中仍然具有极高的价值。它高效、可移植&#xff0c;并广泛用…

选择正确的自动化测试工具:打造高效测试流程的必备利器!

摘要 自动化测试正在逐步取代部分手动测试&#xff0c;因为它可以节省时间并提高测试质量。特别是在进行回归测试的情况下&#xff0c;自动化可以通过多种方式提高效率。手动进行重复测试是浪费时间和资源。此外&#xff0c;由于重复测试可能会遗漏&#xff0c;因此存在一定的…

Android Stuido报错处理

仅用作报错记录。防止以后出项问题不知如何解决。 报错1 Dependency‘androidx.annotation:xx requires libraries and applications … 需要修改CompileSDKVersion更改为报错中提示的版本 打开项目build.gradle文件&#xff0c;将compileSdk和targetSdk修改为报错中提示的版…

从数藏到链游,最近爆火的链游理想城,一天直接干爆服务器!

大家好&#xff0c;我是吴军&#xff0c;一家软件开发公司的营销经理 今天我们来聊聊链游以及数字藏品&#xff0c;2022年4月开始&#xff0c;一众数藏平台犹如雨后春笋冒出来&#xff0c;由ibox牵头&#xff0c;开始了一场掘金盛宴&#xff0c;许多大学生都相继入场&#xff…

【1.7计算机组成与体系结构】主存编址计算

目录 1.主存编址2.主存编址计算公式3.例题&#xff1a; 1.主存编址 1bit(比特位) 1B(字节)8bit(比特位) 1KB1024B 1MB1024KB 1GB1024MB 2.主存编址计算公式 &#x1f534;存储单元 存储单元个数最大地址-最小地址1 &#x1f534;编址内容 按字编址:存储体的存储单元是字存储…

专科毕业,应届生零基础如何七天搞定自动化测试?

现在很多测试人员有些急于求成&#xff0c;没有任何基础想当然的&#xff0c;要在一周内上手自动化测试。 在自动化的过程中时候总有人会犯很低级的问题&#xff0c;有语法问题&#xff0c;有定位问题&#xff0c;而且有人居然连__init__.py 文件名都弄错误&#xff0c;还有将…