Time complexity 衡量一段代码运行时复杂性的最佳实践

Time complexity 衡量一段代码运行时复杂性的最佳实践,time-complexity,Time Complexity,我有一段很粗糙的代码,我想测量它的时间效率。由于从代码本身估计这种复杂性是很困难的,我想把它放在一个循环中,并对结果计时。一旦收集到足够的数据点(大小->时间),我就可以看到哪条曲线最适合 使用给定大小的随机输入数据多次重复操作可以消除操作系统在不好的时刻决定多任务所造成的波动,从而产生更精确的时间。增加问题的大小可以提供更多点,理想情况下间隔良好 我的测试代码运行良好(初始的、非定时的预热循环以减少加载时间;然后,从10开始,以10%的增量放大到1000000,重复运行直到5秒或5次完整运行完

我有一段很粗糙的代码,我想测量它的时间效率。由于从代码本身估计这种复杂性是很困难的,我想把它放在一个循环中,并对结果计时。一旦收集到足够的数据点(大小->时间),我就可以看到哪条曲线最适合

使用给定大小的随机输入数据多次重复操作可以消除操作系统在不好的时刻决定多任务所造成的波动,从而产生更精确的时间。增加问题的大小可以提供更多点,理想情况下间隔良好

我的测试代码运行良好(初始的、非定时的预热循环以减少加载时间;然后,从10开始,以10%的增量放大到1000000,重复运行直到5秒或5次完整运行完成)。然而,我是通过猜测得出这些数字的

是否有一种公认的“科学”方法来衡量重复次数和问题大小,以获得更快、更准确的时间与大小图?是否有代码(或库)可以构建所有枯燥的部分,我在开始自己的工作之前应该知道这些代码?特别是,我可以认为,当发现计时出现颠簸时,可以采取更多措施——而相对平稳的读数可以简单地被认为“足够好”

编辑


我知道计算big-O复杂性的经典方法。它适用于具有良好代表性操作(例如,“比较”或“交换”)的自包含算法。当这些条件不满足时,它不起广告作用(例如:LLVM的编译时C++模板实例化成本,这是一个庞大而复杂的问题,我不知道相关的代表性操作将是什么)。这就是为什么我将其视为一个黑匣子,并试图从外部而不是通过代码检查来测量时间。

测量时间复杂度可能非常困难(如果可能的话),我从未在算法论文中看到过这一点。如果您不能从(伪)代码或算法描述计算时间复杂度,那么您可以使用启发式来简化分析

也许你也可以计算算法某些部分的复杂度,如果其他部分的复杂度明显小得多,就忽略它们

如果没有任何帮助,通常的方法是显示算法在机器上的伸缩性,正如您所写的那样。 但是有很多事情会影响结果。只是为了注意到其中的一些:

  • 内存类型:如果您的输入足够小,可以放入一级缓存,那么您的算法运行得非常快,因为内存很快。如果您的输入变得更大,因此它不再适合一级缓存,它将存储在二级缓存中,如果它变得更大,它将存储在RAM中。每一次你的程序都会因为一个巨大的因素(除了不断增长的输入因素)而减速。最糟糕的是,当它变得如此之大,以至于算法不得不在硬盘上存储一些精简的输入
  • 多任务处理:如果你的操作系统决定将CPU移交给另一个程序,你的算法似乎会变慢。这也很难处理
  • 硬件:在big-O中,每个操作都算作1个时间单位。如果您的算法执行大量CPU优化的操作,这也会影响您的测量
  • 软件:软件可以像硬件一样影响测量。例如,如果你有很多大整数操作使用一个库,你可以通过使用GMP来大幅提高程序的速度
  • 预热:如果你开始测量,你必须先预热CPU。首先在较大的输入上运行算法(无需测量)
  • 输入案例:您只能在特定长度的某些选定或随机生成的输入用例上运行程序。在大多数情况下,很难判断(或根本不可能)输入是否会导致更短或更长的运行时间。所以也许你测试了错误的例子。如果你使用随机输入,你会得到更多不同的结果
总而言之:我认为您只能得到一个想法,即您的算法如何扩展,但您无法通过测量运行时来精确获得复杂性的上限。也许这适用于非常小的示例,但对于较大的示例,您将无法得到正确的结果

您所能做的最好是:

  • 写下用于测量的计算机的确切硬件和软件
  • 重复测试多次(以不同顺序)
  • 如果你改变了硬件或软件,你应该从头开始
  • 只使用存储在同一内存类型中的输入,因此跳过所有适合缓存的情况
通过这种方式,您可以查看更改是否改善了算法,其他人可以验证您的结果

关于输入:

  • 如果可能,您应该使用最坏情况输入。如果不能确定输入是否为最坏情况,则应使用许多不同的情况或随机输入(如果可能)
  • 您必须运行测试(针对每个输入长度),直到运行时间的平均值稳定为止

我不知道有任何用于此的软件,也不知道以前在这方面做过什么工作。而且,从根本上说,我不认为你能得到“O(无论什么)”形式的可信答案。你的测量是有噪声的,你可能试图区分nlog(n)运算和nsqrt(n)运算,并且与一个干净的数学分析不同,所有掉下来的常数仍然在你周围浮动

也就是说,如果我想得出一个最佳估计,我将经历以下过程:

  • 为了确保在整个过程中记录尽可能多的信息,我会在感到无聊之前尽可能多地输入(和大小)来运行我想要测量的东西。可能是一夜之间。对每个输入和大小重复测量
  • 将输入大小铲到时间d