【问题标题】:Does `yield from` have O(1) time complexity?`yield from` 是否具有 O(1) 时间复杂度?
【发布时间】:2020-08-18 20:12:27
【问题描述】:

考虑以下代码 sn-p。

from typing import Iterable


def geometric_progression(
    start: float, multiplier: float, num_elements: int
) -> Iterable[float]:
    assert num_elements >= 0
    if num_elements > 0:
        yield start
        yield from geometric_progression(
            start * multiplier, multiplier, num_elements - 1
        )

这个函数返回几何级数的第一个num_elements,从start开始,每次乘以multiplier。很容易看出,最后一个元素将通过一个 yield-statement 和 num_elements-1 yield-from-statements 传递。此函数是否具有 O(num_elements) 时间复杂度,还是由于深度为 0、1、2、...、num_elements-2、@987654329 的嵌套 yield-from-statements 的“阶梯”而具有 O(num_elements**2) 时间复杂度@?


编辑:我想出了一个更简单的代码 sn-p 来演示我在问什么。

from typing import Iterable, Any

def identity_with_nested_yield_from(depth: int, iterable: Iterable[Any]) -> Iterable[Any]:
    assert depth >= 1
    if depth == 1:
        yield from iterable
    else:
        yield from identity_with_nested_yield_from(depth-1, iterable)

这个函数是O(depth + length of iterable),还是O(depth * length of iterable)

【问题讨论】:

    标签: python yield-from


    【解决方案1】:

    yield fromformally equivalentresponse = yield child.send(response)循环,加上错误传播和处理。在迭代中使用时,response 始终为None,并且不会传播/处理任何错误。这相当于一个for 循环。

    # `yield from child` without error handling/response
    for x in child:
        yield x
    

    因此,每个yield from 都具有迭代其参数的时间/空间复杂性。将大小为n 子级的yield from 堆叠总共m 次因此具有O(nm) 的时间复杂度。

    【讨论】:

      【解决方案2】:

      我可以发誓有一个优化来缩短这些yield from 链,但测试显示没有这样的优化,而且我在我认为优化的地方也找不到任何东西。

      yield from 链的每个级别上的生成器必须单独暂停和恢复,以便在链上上下传递 yieldsend 值。您的函数具有 O(num_elements**2) 时间复杂度。此外,一旦调用堆栈达到 1000 的深度,它就会发生堆栈溢出。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-11-09
        • 1970-01-01
        • 2017-09-01
        • 1970-01-01
        • 2018-03-26
        • 1970-01-01
        • 2015-05-25
        相关资源
        最近更新 更多