【问题标题】:Where did I go wrong in this time complexity calculation?我在这个时间复杂度计算中哪里出错了?
【发布时间】:2017-06-13 15:35:08
【问题描述】:

我在 Python 中有这个函数:

digit_sum = 0
while number > 0:
   digit_sum += (number % 10)
   number = number // 10

为了确定时间复杂度,我应用了以下逻辑:

第 1 行: 1 个基本操作(赋值),被执行 1 次,因此得到的值为 1

第 2 行: 2 个基本操作(读取变量“数字”并与零进行比较),执行 n+1 次,因此得到 2*(n+1) 的值

第 3 行: 4 个基本操作(读取变量“数字”、%10、计算总和和赋值),被执行 n 次,因此得到 4*n 的值

第 4 行: 3 个基本操作(读取变量 'number'、//10 和赋值),被执行 n 次,因此得到值 3*n

这使我总共有 1 + 2n+2 + 4n + 3n = 9n+3

但是我的教科书有一个8n+3的解。我的逻辑哪里出错了?

谢谢,

亚历克斯

【问题讨论】:

  • 嗯,它线性的。这就是你真正需要知道的一切。
  • 没错,但我想看几个例子,它是这样计算的,每行一行。
  • 谈到复杂性时,您真正关心的是asymptotic complexity。这里,O(n)。 8 或 9 或 42 并不重要,尤其是因为您无法知道。例如,分配很可能比除法花费的时间要少得多,因此仅将两者都视为一个操作是没有意义的。 // 不管怎样,从你对计数的描述来看,你的逻辑是正确的。
  • 我知道这没关系,但是没有办法告诉我在我的逻辑中哪里出错了?因为在我的教科书中,他们说:“第 2 行 = 2 次操作”、“第 3 行 = 4 次操作”和“第 4 行 = 2 次操作”,我想知道为什么可以这样做。 // 如果计数正确,那很好:)
  • 长话短说:因为计算“操作”是没有意义的。它公开了底层处理器的架构细节(无论是实际的 hw proc 还是解释器)。真正获得“真实”操作计数的唯一方法是查看特定实现(例如,CPython 3.6.0)并查看它从您的程序生成的字节码。

标签: python time-complexity


【解决方案1】:

在谈论复杂性时,您真正关心的是asymptotic complexity。这里,O(n)。 8 或 9 或 42 并不重要,尤其是因为您无法知道。

因此计算“操作”是没有意义的。它公开了底层处理器的架构细节(无论是实际的 hw proc 还是解释器)。真正获得“真实”操作计数的唯一方法是查看特定实现(例如,CPython 3.6.0)并查看它从您的程序生成的字节码。

这是我的 CPython 2.7.12 所做的:

>>> def test(number):
...     digit_sum = 0
...     while number > 0:
...         digit_sum += (number % 10)
...         number = number // 10
...
>>> import dis
>>> dis.dis(test)
  2           0 LOAD_CONST               1 (0)
              3 STORE_FAST               1 (digit_sum)

  3           6 SETUP_LOOP              40 (to 49)
        >>    9 LOAD_FAST                0 (number)
             12 LOAD_CONST               1 (0)
             15 COMPARE_OP               4 (>)
             18 POP_JUMP_IF_FALSE       48

  4          21 LOAD_FAST                1 (digit_sum)
             24 LOAD_FAST                0 (number)
             27 LOAD_CONST               2 (10)
             30 BINARY_MODULO
             31 INPLACE_ADD
             32 STORE_FAST               1 (digit_sum)

  5          35 LOAD_FAST                0 (number)
             38 LOAD_CONST               2 (10)
             41 BINARY_FLOOR_DIVIDE
             42 STORE_FAST               0 (number)
             45 JUMP_ABSOLUTE            9
        >>   48 POP_BLOCK
        >>   49 LOAD_CONST               0 (None)
             52 RETURN_VALUE

我让你得出你自己的结论,你想要什么实际上算作基本操作。 Python 解释器一个接一个地解释字节码,所以可以说你的循环中有 15 个“基本操作”。这是您可以获得的最接近有意义的数字。尽管如此,其中的每个操作都有不同的运行时间,因此 15 没有任何有价值的信息。

另外,请记住,这是特定于 CPython 2.7.12 的。另一个版本很可能会生成其他东西,利用新的字节码可能使以更简单的方式表达某些操作成为可能。

【讨论】:

    猜你喜欢
    • 2020-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-20
    相关资源
    最近更新 更多