Algorithm 大(O)可以通过测量来确认吗?

Algorithm 大(O)可以通过测量来确认吗?,algorithm,big-o,Algorithm,Big O,假设您已经设计了一个算法,您可能认为它在O(n)中运行。如果我用1000个输入测量它运行的时间,然后将输入增加10倍,然后再次测量。如果运行时间几乎是第一次尝试的10倍,我能推断O(n)是正确的吗 这有多愚蠢?显然,重复测试会提高准确性,但我想知道这是否有意义。通常,答案是“是”。如果你把问题的大小增加10,时间增加10,那么你假设O(N)可能是正确的。然而,这个数字不太可能如此美丽 如果从1000到10000,O(N.logN)算法大约会增加13倍(参见下面的bc)。这离10不远,你可能会错误

假设您已经设计了一个算法,您可能认为它在O(n)中运行。如果我用1000个输入测量它运行的时间,然后将输入增加10倍,然后再次测量。如果运行时间几乎是第一次尝试的10倍,我能推断O(n)是正确的吗


这有多愚蠢?显然,重复测试会提高准确性,但我想知道这是否有意义。

通常,答案是“是”。如果你把问题的大小增加10,时间增加10,那么你假设O(N)可能是正确的。然而,这个数字不太可能如此美丽

如果从1000到10000,O(N.logN)算法大约会增加13倍(参见下面的
bc
)。这离10不远,你可能会错误地认为增加12表示O(N.logN)而不是O(N)。然而,如果你增加10,时间大约增加100,你很可能在处理一个非线性算法——O(N2)。因此,2分是不够的,但它是指示性的。多次运行和更多数据点都有帮助

不过,有时候,会有别的事情发生。例如,您可能突然开始使用太多内存,以至于程序被分页,而不是仅仅运行。即使给定足够的资源,该算法仍然是线性的,它也会显著减慢速度

此外,还要注意缓存效果和优化效果。缓存可以使事情看起来更快。如果优化器得出忽略计算的结论,则可能会消除整个计算。所以你必须小心

但是,如果运气好的话,你可以将问题放大几个数量级(或者,至少是几个不同的数字),然后合理地猜测它是线性的还是其他的

O(N.logN)表示1000对10000
与另一个答案相反,我会说“不”。然而,你可以得到一个很好的猜测(甚至不是一个估计,因为它在这里是不合适的)。这可能就是“经常”的意思

问题是,你永远不知道常数。大Oh是无症状行为(在无穷大范围内),这是一个非常有用的方法,可以删除除最长期限之外的所有内容。所以从数学上来说,你无法证实你的假设

首先,当无症状行为在实际应用中没有用处时,这里有大量的算法和用例。仅仅是因为“典型用例”输入分布下降了。这种情况更常见。你仍然可以测试/估计它

但也有一种情况是,最好的算法具有如此大的常数因子,因此不适用于现代系统。我所知道的最好的例子是

然而,有些系统“近似”(更确切地说是猜测)算法的复杂度。我不确定Codibility是测量它还是通过代码分析得到他们的猜测,但他们能够做到:

我们可以做的是运行一个算法,改变输入大小,运行测试并使数据适合模型。这很简单。然后,您可以说,对于测试的输入范围,算法表现为
O(class(n))
。(这可能比理论上的渐进复杂性更有实际意义。)

请注意,选择测试点并非易事。基本上,如果您的算法表现得“快”,那么您需要增加下一个类的输入大小速率。例如,如果你有类似于
(100n+n!)
的东西,你可以去
n={1,10100}
,因为它将
杀死执行时间。然而,继续
n={1,2,3,4,5,6,7}
将不会拾取
n部分(ok
7!
5040
但是对于
n^2
则要困难得多)

底线是,得到一个好的猜测当然是可能的,但除了大多数简单的情况下,这可能是棘手的,很难做到,可悲的是,很难判断这个案件是否棘手


此外,此讨论纯粹是理论性的,跳过了硬件效果。我听说过
n^2
n^log n
表现更好的算法,因为前者总是(非常)缓存友好的,但不要相信我的话,我记不起源代码。

根据实际程序的运行时绘制输入大小是一个非常有用的工具,可以让您查看代码的实际执行情况。一般来说,认为可以用它来推断复杂性是危险的

下面是一个实际的例子,说明了它的一种故障方式

好的快速排序实现将数组分为三个部分:小于轴、等于轴和大于轴。这意味着对随机数组64位整数进行快速排序(实际上,对任何固定大小数据类型的随机数组进行排序)会使用O(n)比较,因为最终每个子数组都是常量

不幸的是,您无法从经验上看到这一点:如果您根据比较的数量绘制n,那么图形看起来就像n*log(n),直到输入数组变得远远大于2^64个元素。即使您有足够的内存,您的编程语言也可能不允许您对这种大小的数组进行索引


这个例子还表明,经验测量为您提供了有趣的数据(代码在实际输入上的表现类似于n*log(n)),复杂性为您提供了一个理论上但实际上毫无用处的关于渐近增长是线性的事实。

除了其他人所说的之外。有时,平均情况和最坏情况可能不同,最坏情况可能很难找到。一个著名的例子是
quicksort
,它的
O(n log n)
平均行为(滥用
O
符号?)和
O(n^2)
最坏情况行为。如果给你一个“黑箱”算法(好吧,程序),在没有算法知识的情况下,这种最坏的情况可能很难通过实验捕捉到。

通常,答案是“是”。如果你把问题的大小增加10,时间增加10,你可能就没事了。然而,这个数字不太可能如此
$ bc -l
n=1000
n*l(n)
6907.75527898213705205000
a=n*l(n)
m=n*10
m*l(m)
92103.40371976182736070000
b=m*l(m)
b/a
13.33333333333333333333
quit
$