【问题标题】:Calculating Big O Notation with Recursion用递归计算大 O 表示法
【发布时间】:2017-11-21 03:48:19
【问题描述】:

我试图理解 Big O Notation 最坏情况运行时。 但我还是不太明白。

这是我最近写的一些代码:

def g(n):
    if n==0:
        return 1
    elif n==1:
        return 2
    else:
        n_div=n//2
        n_mod=n%2
        return g(n_div)*g(n_mod)

所以我希望我至少是对的:

def g(n):
    if n==0:
        return 1

和:

elif n==1:
    return 2

是 O(1),所以是恒定的。

但是else 部分呢。

它是 O(n),因为它取决于我选择的 n 吗?

谁能解释 else 部分的大 O 复杂性是什么?

【问题讨论】:

    标签: python python-3.x big-o notation


    【解决方案1】:

    嗯,您已经注意到您可以将您的函数分成 3 个单独的案例,并且已经确定前 2 个是 O(1)。第三个稍微复杂一些,但您也可以将其分成两部分。

    递归显然发生在:

    g(n//2)*g(n%2)
    

    我们可以立即看到n%2 将评估为 0 或 1,这将再次解决前两种情况之一,因此我们可以忽略它。留下我们g(n//2)。通过将其重写为打印循环并检查输出,您会注意到一些事情:

    >>> n = 37
    >>> while n > 1:
    ...     n //= 2
    ...     print(n)
    ...
    18
    9
    4
    2
    1
    

    正如您所见,项每次减少一半,递归中也会发生同样的情况。这是对数

    因此,这个函数的最坏情况是 O(logn)。

    您可以通过查看this question 了解更多关于 logn 在 Big-O 表示法中的实际含义。

    【讨论】:

    • 有计算二进制码中1的函数吗?
    【解决方案2】:

    O 表示法并不真正用于程序的一部分。它确实衡量了运行时间随着输入大小的增加而增加的方式。在这种情况下,耗时的部分是最后的 else 部分。

    您需要了解这对您的程序有何作用。这是一个简单的经验分析,应该对您有所帮助。如果我们稍微检测一下程序以打印出最终else 部分针对给定输入运行了多少次,我们就会得到这个。

       n | times
    -----+-----
       2 | 1
       4 | 2
       8 | 3
      16 | 4
      32 | 5
      64 | 6
     128 | 7
     256 | 8
     512 | 9
    1024 | 10
    2048 | 11
    4096 | 12
    8192 | 13
    

    如果你绘制这个,你会看到类似的东西。

    您可以看到,随着输入大小的增加,调用次数也会增加,但呈次线性增加。事实上,它是对数的,因为您的 n 每次循环迭代都会减少 50%。

    【讨论】: