这种基于Python生成器的顺序遍历方法的工作原理
我对python还很陌生,还在探索。遇到生成器,下面是使用生成器实现有序二叉树遍历的代码段:这种基于Python生成器的顺序遍历方法的工作原理,python,Python,我对python还很陌生,还在探索。遇到生成器,下面是使用生成器实现有序二叉树遍历的代码段: def inorder(t): if t: for x in inorder(t.left): yield x yield t.label for x in inorder(t.right): yield x 现在我知道了关于生成器的以下事实:它们记住调用中的局部变量值。然而,这个函数是递归的。
def inorder(t):
if t:
for x in inorder(t.left):
yield x
yield t.label
for x in inorder(t.right):
yield x
现在我知道了关于生成器的以下事实:它们记住调用中的局部变量值。然而,这个函数是递归的。那么它如何在这些不同的递归调用中记住局部变量值呢
另外,很容易理解正常的递归顺序程序(不涉及生成器),因为有明确指定的递归终止条件。但是这种使用生成器的递归是如何工作的呢?
按顺序返回生成器。该对象在调用next
之间记住其本地状态。通过单独调用顺序创建的生成器之间没有重叠,即使递归调用也是如此。我对代码进行了一些修改,以了解执行序列的流程。基本上我添加了一些print()
语句
class BinaryTreeNode():
def __init__(self, pLeft, pRight, pValue):
self.left = pLeft
self.right = pRight
self.label = pValue
def inorder(t):
print("at the beginning of inorder(t): " + (str(t.label) if t else "None" ))
if t:
for x in inorder(t.left):
print("inside inorder(t.left):" + str(t.label)) #delete
yield x
print("inside inorder(t):" + str(t.label)) #delete
yield t.label
for x in inorder(t.right):
print("inside inorder(t.right):" + str(t.label)) #delete
yield x
node1 = BinaryTreeNode(None,None,1)
node3 = BinaryTreeNode(None,None,3)
node2 = BinaryTreeNode(node1,node3,2)
node5 = BinaryTreeNode(None,None,5)
node4 = BinaryTreeNode(node2,node5,4)
root = node4
for i in inorder(root):
print(i)
输出为:
1 at the beginning of inorder(t): 4
2 at the beginning of inorder(t): 2
3 at the beginning of inorder(t): 1
4 at the beginning of inorder(t): None
5 inside inorder(t):1
6 inside inorder(t.left):2
7 inside inorder(t.left):4
8 1
9 at the beginning of inorder(t): None
10 inside inorder(t):2
11 inside inorder(t.left):4
12 2
13 at the beginning of inorder(t): 3
14 at the beginning of inorder(t): None
15 inside inorder(t):3
16 inside inorder(t.right):2
17 inside inorder(t.left):4
18 3
19 at the beginning of inorder(t): None
20 inside inorder(t):4
21 4
22 at the beginning of inorder(t): 5
23 at the beginning of inorder(t): None
24 inside inorder(t):5
25 inside inorder(t.right):4
26 5
27 at the beginning of inorder(t): None
请注意,对inorder(node4)
的第二次调用没有在inorder(t):4的开头打印,而是在inorder(t)的开头打印:None
(输出中的第9行)。这意味着生成器还记得最后执行的行(主要是因为它记得最后一次调用中的程序计数器值)
此外,每个for循环都从函数inoorder()
获取生成器实例。该生成器特定于for循环,因此本地范围是单独维护的
上面横穿了这棵树:
4
/ \
2 5
/ \
1 3
当每个递归调用到达其结束时,也会发生终止。这将导致以下递归调用树:
==>inorder(<4>)
|---> x in inorder(left<2>)
|---> x in inorder(left<1>)
|---> x in inorder(left<None>) --> terminate
yield 1 (note the indention, it is not yield inside first for-in loop but after it)
yield 1 (note the indentation, this is yield inside first for-in loop)
yield 1
inorder(<4>)
|---> x in inorder(left<2>)
|---> x in inorder(left<1>)
==============================>|---> x in inorder(right<None>) --> terminate
yield 2
yield 2
inorder(<4>)
|---> x in inorder(left<2>)
================>|---> x in inorder(right<3>)
|---> x in inorder(left<None>) --> terminate
yield 3
yield 3
yield 3
inorder(<4>)
|---> x in inorder(left<2>)
|---> x in inorder(left<1>)
=============================>|---> x in inorder(right<None>) --> terminate
terminate
terminate
yield 4
inorder(4)
==>|---> x in inorder(right<5>)
|---> x in inorder(left<None>) --> terminate
yield 5
yield 5
inorder(4)
|---> x in inorder(right<5>)
===============>|---> x in inorder(right<None>) --> terminate
terminate
terminate
terminate
==>顺序()
|--->顺序中的x(左)
|--->顺序中的x(左)
|--->顺序中的x(左)->终止
收益率1(注意缩进,它不是循环内第一个收益率,而是循环后的收益率)
屈服1(注意压痕,这是回路中第一个内部屈服)
收益率1
顺序()
|--->顺序中的x(左)
|--->顺序中的x(左)
==================================>|-->顺序中的x(右)-->终止
收益率2
收益率2
顺序()
|--->顺序中的x(左)
=============>|-->按顺序输入x(右)
|--->顺序中的x(左)->终止
收益率3
收益率3
收益率3
顺序()
|--->顺序中的x(左)
|--->顺序中的x(左)
==================================>|-->顺序中的x(右)-->终止
终止
终止
收益率4
顺序(4)
==>|-->x按顺序排列(右)
|--->顺序中的x(左)->终止
收益率5
收益率5
顺序(4)
|--->顺序中的x(右)
================>|-->顺序中的x(右)-->终止
终止
终止
终止
(解释:
表示以nodei
为参数的调用
left
表示inoder(t.left)
在t.left
为nodei
right
表示inoder(t.right)
在t.right
为nodei
==>
显示在该特定调用中执行从何处开始)