Computer science 终止算法时间复杂度的自动计算

Computer science 终止算法时间复杂度的自动计算,computer-science,big-o,code-analysis,time-complexity,halting-problem,Computer Science,Big O,Code Analysis,Time Complexity,Halting Problem,这里有很多相关的问题,但是他们都要求编写一个程序来计算任意算法的复杂性(这显然是不确定的)。我愿意对输入做出以下限制: 算法终止 该算法纯粹是功能性的 问题是,是否可以编写一个程序,通过静态分析计算这种算法的时间复杂度?如果输入算法未终止,则程序行为未定义(可能会崩溃、返回谎言或无法终止)。如果算法停止,则有可能。对每个可能的输入执行算法,并测量执行时间。接下来,选择一个函数作为可能的上边界,并对每个结果进行测试。如果不够好,增加边界并重新测试。重复,直到边界足够好 编辑: 此解决方案假设实际计

这里有很多相关的问题,但是他们都要求编写一个程序来计算任意算法的复杂性(这显然是不确定的)。我愿意对输入做出以下限制:

  • 算法终止
  • 该算法纯粹是功能性的

  • 问题是,是否可以编写一个程序,通过静态分析计算这种算法的时间复杂度?如果输入算法未终止,则程序行为未定义(可能会崩溃、返回谎言或无法终止)。

    如果算法停止,则有可能。对每个可能的输入执行算法,并测量执行时间。接下来,选择一个函数作为可能的上边界,并对每个结果进行测试。如果不够好,增加边界并重新测试。重复,直到边界足够好

    编辑
    此解决方案假设实际计算机程序的边界,即不同输入的数量不是无限的。否则,就不可能计算通用算法的复杂度。考虑复杂度为<>代码> o(n)=n <代码> o(n-1)的算法。由于输入是无限的,您将无法找到任何可以限制复杂性的函数。

    您无法100%确定您从任何基于实际运行时间估计复杂性的技术中得到正确答案。这是因为精确的运行时间可能涉及一个非常复杂的函数,这意味着当输入大小低于某个非常大的数字时,运行时间理论上可以遵循任何其他函数。当输入大小趋于无穷大时,运行时间只需要趋向复杂度函数的(某些倍数)。这假设您想要找到一个(存在于许多算法中,但不是所有算法中)而不仅仅是一个上限或下限

    但是你可以对复杂度做出一些合理的估计,通常应该是相当准确的

    还请注意,对于相同大小的不同输入,许多算法具有不同的运行时间。您可以尝试为相同大小的几个不同输入运行下面的命令,并平均结果以缓解此问题。这也有助于缓解可能影响运行时间的系统状况。尽管如果您不知道用于最坏和最佳情况的具体输入,您可能无法估计其复杂性(因为它们可能太少,您在传递随机数据时无法获得它们)

    如何操作:

    记录一些足够大且大小足够不同的输入的时间(例如,您可以对大小等于10的不同幂次的输入运行时间,如100、1000和10000,这些输入的大小应足以使其运行至少几秒钟,以降低数据的噪音)。让我们使用3种输入大小。严格来说,您只需要2个输入大小,但可以使用3个或更多作为附加验证

    现在我们可以尝试将这3个结果映射到一些复杂集合中的一个,比如
    O(1)
    O(log(n))
    O(sqrt(n))
    O(n)
    O(n log n)
    O(n2)
    O(n3)
    ,等等

    如果您试图手动匹配它,您可以将获得的运行时间与上述每个函数的图形一起放在一个图形上(适当缩放),然后查看哪一个匹配得最好

    如果您试图将其自动化,您可以尝试将每个函数映射到输入大小,并查看其匹配程度

    有更好的方法可以做到这一点,但真正简单的方法如下:

    假设您有以下运行时间:

    input size   running time
    100          21 seconds
    1000         29 seconds
    10000        40 seconds
    
    现在,您可以尝试将其中一个(比如最大的一个,可能是最精确的)与上述函数的倍数进行匹配

    O(n):     k x n     = k x 10000     = 40,    k = 40 / 10000     = 0.004
    O(log n): k x log n = k x log 10000 = 40,    k = 40 / log 10000 = 10
    O(n²):    k x n²    = k x 10000²    = 40,    k = 40 / 10000²    = 0.0000004
    
    现在,将等式给出的值与其他输入大小的实际运行时间进行比较:

    For n = 1000, actual running time = 29 seconds
    O(n):     0.004 x 1000      = 4 seconds
    O(log n): 10 x log 1000     = 30 seconds
    O(n²):    0.0000004 x 1000² = 0.4 seconds
    
    For n = 100, actual running time = 21 seconds
    O(n):     0.004 x 100      = 0.4 seconds
    O(log n): 10 x log 100     = 20 seconds
    O(n²):    0.0000004 x 100² = 0.004 seconds
    

    看看这个,我们可以清楚地看到,
    O(logn)
    是最接近的,在这两种情况下,实际和预测的运行时间相差仅1秒。这就是我们对复杂性的猜测。

    我终于在正确的地方问到了问题,并得到了答案。没有


    您能编辑并实际提出一个可以回答的问题吗?我看到了需求声明,但没有实际问题。@KenWhite问题在标题中,但我已经更新,以便在正文中更清楚地说明:):-)我读了标题中的声明(一点问题也没有)。现在你问的问题更清楚了。谢谢,还有+1.为什么不令人满意?这个问题纯粹是理论问题,答案也是。我想它可以被优化,但我不认为这样做的理由,我会在一个实际的解决方案中找到价值——你能想象编译器对无意中的n**3算法发出的警告吗?但作为一个理论上的答案,在寻找边界函数的启发式方法中,它仍有一些不足之处。不过,我承认,这个设置并没有提供太多改进的动力。我想说的是,找到一个通用算法是否以O(n3)为界至少需要O(n3)计算,无论是在编译时还是在运行时—我认为在正常情况下,这两种方法都是不可接受的。这种解决方案不太可能在大多数终止输入上终止(因为可能的输入通常是无限的),而且也不是很严格,主要是一种启发式方法。@singpolyma我编辑了答案,以解决您提出的问题。