【问题标题】:python generators time complexity confusionpython生成器时间复杂度混淆
【发布时间】:2016-12-30 18:15:18
【问题描述】:

我一直在阅读有关关键字 yield 和 python 中的生成器的信息,我想知道我是否正确理解了它的时间复杂度。

这是我获取因子的生成器函数:

def calc_factors(n):
    for k in range(0, n+1):     # this is the second "for" loop
        if n % k == 0:
           yield k

我将这个生成器函数称为:

>>> for factor in calc_factor(100):   # this is the first "for" loop
        print factor

现在我的理解是,它的时间复杂度为 O(n^2),因为它有两个 for 循环,但我还是不相信。请在这方面启发我。 提前致谢!

【问题讨论】:

  • 您不能只计算程序中的循环数并将计数放在 n^ 旁边。时间复杂度不是那样工作的。
  • 虽然从语法上讲,您有两个循环,但生成器中的循环只有一次迭代会在生成器外循环的每次迭代中执行。花费的总时间与 n 成正比,而不是 n^2。
  • @user2357112 :感谢您的评论。我很困惑,因为它看起来像第一个 for 循环执行然后它会调用生成器函数但是生成器函数有另一个 for 循环让我这么想。我同意计算for 循环不是判断时间复杂度的正确方法。

标签: python data-structures time-complexity generator


【解决方案1】:

你误会了。你有一个 O(n) 循环。生成器函数上的循环不是嵌套循环,它只是在生成器生成时从生成器接收每个项目。

换句话说,for factor in calc_factor(100) 循环直接连接到yield k 表达式;每次执行for factor in calc_factor(100) 循环都会前进一步。对于每个执行的 yield k 表达式,您将获得 1 个 factor 值。 yield k 执行(最多)n 次,仅此而已。

您可以在不过多歪曲事实的情况下,将for factor in calc_factor(100) 循环体中的所有代码替换 yield k 行,替换为factor = k。在您的情况下,您只使用print factor,因此您可以将yield k 替换为print k,而不会丢失功能。

如果你想以不同的方式看待它,请拿走生成器并建立一个列表。这就是您的代码在这种情况下所做的:

results = []
for k in range(0, n+1):
    if n % k == 0:
       results.append(k)

for factor in results:
    print factor

现在你仍然有两个循环,但它们没有嵌套。一个是 O(n) 循环来构建列表,另一个是 O(k) 循环(k O(n))。

生成器所做的只是删除中间列表。您不必先收集所有结果,您可以立即访问每个结果。

【讨论】:

  • 所以不考虑calc_factor(n) 内的for 循环?
  • @d-coder:当然是。但是生成器结果 over 的循环并不是一个新循环。每次您单步执行下一个结果(这将使其变为 n**2)时,您不会在 calc_factor() 中运行 all 循环,而是单步执行生成器的所有结果。
  • 非常感谢您的回答。你的回答消除了我的困惑。
【解决方案2】:

不,这应该只有 O(n) 的时间复杂度。

在真正的嵌套循环中,外循环的每次迭代都会导致内循环的完整组迭代:

for i in range(100):      # 100 times
    for j in range(i):    # i times, for *each* of the 100 values of i
         # do something

但在生成器中,yield 语句会导致生成器立即返回控制权。所以每次迭代生成器只计为一个通过生成器的循环。

所以你的for factor in calc_factor(100): 调用生成器每个生成器循环的实例。所以从某种意义上说,这就是生成器的循环;它只是从发电机本身的外部控制。因此它不是一个外部嵌套循环。

【讨论】:

  • 感谢您的回答。我想我的困惑已经消除了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-11-29
  • 1970-01-01
  • 2021-03-05
  • 2017-09-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多