微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

当递归使用yield时,是否创建n个迭代器?

如何解决当递归使用yield时,是否创建n个迭代器?

考虑:

def iterInorder(node):
    if node.left:
        for n in iterInorder(node.left):
            yield n
    yield node
    if node.right:
        for n in iterInorder(node.right):
            yield n

并让n为输入二叉树中的节点数,是否创建一个生成n个节点的单个生成器?还是创建n迭代器,每个迭代器生成一个节点?与简单的递归旅行相比,您能说出该代码的时空复杂度如何?

def visitInorder(node):
    if node.left:
        visitInorder(node.left)
    visit(node)
    if node.right:
        visitInorder(node.right)
                

我更关心Python 2,但很高兴知道答案是否与Python 3不同。

解决方法

在CPython中,对iterInOrder()的每次调用都会创建一个新的generator-iterator,而与Python版本无关,无论它是顶级调用还是递归调用。

类似地,每次调用visitInOrder()都会创建一个新的堆栈框架,而与Python版本或上下文无关。

因此,空间复杂度无论哪种方式都是O(depth(tree))(通常与节点数量没有有用的关系-树的深度可能是n层,或者是2层)。

时间是一种不同的计算方式,但微妙的是因为它几乎从未引起注意:递归版本具有O(n)的时间复杂度,但这在生成器版本上有一个下限。每次yield时,产生的值都会一次递归传递到递归生成器调用链中,直到最终被顶级调用消耗为止。然后,当链恢复时,生成器-迭代器框架的堆栈一次被重新激活,直到回到原始的yield

因此,在生成器版本中,depth(tree)中有一个二次时间分量。但是除非这棵树很深,否则您可能永远不会注意到这一点,因为在CPython中,所有堆栈展开和倒回都是“以C速度”进行的。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。