Java 估计实现的实际(非理论)运行时复杂性

Java 估计实现的实际(非理论)运行时复杂性,java,complexity-theory,benchmarking,caliper,microbenchmark,Java,Complexity Theory,Benchmarking,Caliper,Microbenchmark,计算机科学界的任何人都会知道HeapSort在理论上是O(n logn)最坏的情况,而QuickSort是O(n^2)最坏的情况。然而,在实践中,一个实现良好的快速排序(具有良好的启发式)将在每个数据集上都优于HeapSort。一方面,我们几乎没有观察到最坏的情况,另一方面,CPU缓存线、预取等在许多简单任务中产生了巨大的差异。例如,快速排序可以处理O(n)中的预排序数据(具有良好的启发性),而HeapSort将始终在O(n log n)中重新组织数据,因为它不会利用现有结构 对于我的玩具项目,

计算机科学界的任何人都会知道HeapSort在理论上是
O(n logn)
最坏的情况,而QuickSort是
O(n^2)
最坏的情况。然而,在实践中,一个实现良好的快速排序(具有良好的启发式)将在每个数据集上都优于HeapSort。一方面,我们几乎没有观察到最坏的情况,另一方面,CPU缓存线、预取等在许多简单任务中产生了巨大的差异。例如,快速排序可以处理
O(n)
中的预排序数据(具有良好的启发性),而HeapSort将始终在
O(n log n)
中重新组织数据,因为它不会利用现有结构

对于我的玩具项目,我最近一直在研究根据基准测试结果估计算法实际平均复杂度的方法。特别是,我用不同的多项式尝试了劳森和汉森的NNLS拟合

然而,它还不能很好地工作。有时候我得到了有用的结果,有时候我没有。我认为只做更大的基准测试可能会有所帮助,特别是尝试更多的参数

以下结果用于以随机性为10%的SAW模式对双对象进行排序。n在这次运行中仅达到500,因此它在实际使用中不是很有代表性。。。这些数字是对大小的估计运行时依赖关系。输出是手动编辑和手动排序的,因此它不反映工具当前提供的内容

BubbleSortTextbook       LINEAR: 67.59  NLOG2N:  1.89  QUADRATIC: 2.51
BubbleSort               LINEAR: 54.84                 QUADRATIC: 1.68
BidirectionalBubbleSort  LINEAR: 52.20                 QUADRATIC: 1.36
InsertionSort            LINEAR: 17.13  NLOG2N:  2.97  QUADRATIC: 0.86
QuickSortTextbook                       NLOG2N: 18.15
QuickSortBo3             LINEAR: 59.74                 QUADRATIC: 0.12
Java                     LINEAR:  6.81  NLOG2N: 12.33
DualPivotQuickSortBo5                   NLOG2N: 11.28
QuickSortBo5             LINEAR:  3.35  NLOG2N:  9.67
您可以看出,虽然在这个特定的设置中(通常它根本不能令人满意),但结果基本上与已知的行为一致:冒泡排序的成本非常高,而快速排序的良好启发式方法要好得多。但是,例如,如果快速排序的中位数为三个启发式,则会得到一个
O(n+n^2)
估计值,而其他快速排序的估计值为
O(n+n log n)

现在我要问的问题是:

  • 您知道从基准数据执行运行时复杂性分析的算法/方法/工具吗?这些算法/方法/工具可以预测哪种实现(正如您在上面看到的,我对比较同一算法的不同实现感兴趣!)在真实数据上表现最好
  • 您是否知道与此相关的科学文章(估计实现的平均复杂性)
  • 你知道稳健的拟合方法有助于获得更准确的估计吗?例如,NNLS的规范化版本
  • 你知道一个人需要多少样本才能得到合理估计的经验法则吗?(特别是,工具什么时候应该避免给出任何估计,因为它可能无论如何都不准确?)
让我再次强调,我对理论复杂性或形式分析不感兴趣。我感兴趣的是看到(理论上甚至是相同算法的)实现如何在真实CPU上对基准数据执行与渐近行为相比,我更感兴趣的是共同范围内的数值因子。(不,从长远来看,这不仅仅是时间复杂度和排序。我对索引结构和其他参数感兴趣。如果我没有弄错的话,卡钳还可以测量内存消耗)另外,我在java中工作。一种只调用Matlab内置函数的方法对我没有用,因为我不生活在Matlab世界中


如果我有时间,我会尝试用更大的尺寸重新运行其中一些基准测试,以便获得更多的数据点。也许这样就行了。。。但我相信有更稳健的回归方法,我可以用它从更小的数据集中得到更好的估计。另外,我想检测样本是否太小而无法进行任何预测

如果你想了解实际的复杂性,最好是对其进行测量。在不进行测量的情况下,试图猜测程序将如何运行是非常不可靠的

同一个程序在不同的机器上执行的方式可能非常不同。e、 一个算法在一台机器上可能更快,但在另一台机器上可能更慢

您的程序可能会变慢,这取决于机器正在执行的其他操作。一个看起来不错但大量使用缓存等资源的algo可能会变慢,并且在必须共享这些资源时会使其他程序变慢

在机器上单独测试algo比在实际程序中使用algo快2-5倍

你知道一个人需要多少样本才能得到合理估计的经验法则吗?(特别是,工具什么时候应该避免给出任何估计,因为它可能无论如何都不准确?)


要确定90%或99%的百分比,您需要1/(1-p)^2,即对于99%的瓷砖,您需要在预热后至少10000个样品。99.9%的瓷砖需要一百万。

@JimGarrison不一定。OP一直强调他对理论部分不太感兴趣…更适合或更真实,但这个问题不是关于编程,而是关于算法评估。尽管这种方法是经验性的,但更多的是统计学和[应用]理论。它并不真正适用于TCS,因为我假设的是一个黑盒算法模型。在简历上,我的印象是解决方案不会太实用。因此,更多的是在实际代码中实现这些东西。理论上可行的解决方案对我帮助不大。理论上,NNLS应该做这项工作,但在实践中,它并没有真正发挥足够的作用;它可能不够健壮。离群值,并且在同一个n处的多个测量值中没有很好地表现出来?@Raedwald我认为他在最后的列表中很好地总结了这些问题:在给定一组基准测试结果的情况下,如何编写一个程序来自动估计算法的可伸缩性。但他实际上不是在尝试这样做:自动化此类测试吗?从基准数据估计复杂性听起来很像,IMHO.的确如此。我是阿尔