实际计算算法的时间复杂度

时间:2013-06-03 09:29:58

标签: java algorithm sorting

我只是在理论上读过关于时间的复杂性..有没有办法在程序中计算它们?不是像'n'或其他任何假设,而是通过实际值。

例如..计算合并排序和快速排序的时间复杂度..

Merge Sort= O(nlogn);// any case

Quick Sort= O(n^2);// worst case(when pivot is largest or smallest value)

nlogn和n ^ 2在数学上存在巨大差异..

所以我在我的程序中试过这个..

main()
    {
       long t1=System.nanoTime();
       // code of program..
       long t2=System.nanoTime();
       time taken=t2-t1;
    }

我得到的两种算法的答案,实际上我试过的任何算法都是20。

System.nanoTime()不够精确还是我应该使用较慢的系统?或者还有其他方法吗?

7 个答案:

答案 0 :(得分:4)

  

有没有办法在程序中计算它们?不是像'n'或其他任何假设,而是通过实际值。

我认为你误解了复杂性是什么。这不是一个价值。它甚至不是一系列价值观。这是一个公式。如果你摆脱N它作为复杂性度量是没有意义的(除了O(1) ......显然)。


一方面设置该问题,理论上可以自动化对复杂性的严格分析。然而,这是一个难题:自动化定理证明是困难的......特别是如果循环中没有人来“指导”这个过程。 Halting定理意味着不能有一个能够证明任意程序复杂性的自动定理证明器。 (当然,没有一个复杂性证明器适用于可能会或可能不会终止的所有程序...)


但是有一种方法可以计算具有给定输入集的程序的性能度量。你跑吧!事实上,你会进行一系列的运行,根据某些问题规模度量(即N)来绘制表现图......并对与绩效和N度量相关的公式进行有根据的猜测。或者您可以尝试将测量值拟合到公式中。

然而......

  • 这只是猜测而且
  • 这种方法并不总能奏效。

例如,如果您在经典Quicksort上尝试此操作,您很可能会认为复杂性为O(NlogN),并且错过了一个重要的警告:“最坏情况”是O(N^2)。另一个例子是当问题规模变大时,可观察的性能特征改变

简而言之,这种方法很可能会给你不可靠的答案。

答案 1 :(得分:2)

嗯,在实践中对程序有一些假设,你可能能够在大量测试用例上运行你的程序(并测量它花费的时间)并使用插值来估计程序的增长率和复杂性,并使用statistical hypothesis testing来显示您的正确概率。

然而,在所有情况下都无法做到这一点。事实上,你甚至不能有一个算法告诉每个程序它是否要暂停(运行一个无限循环)。这被称为Halting Problem,它被证明是可以解决的。

答案 2 :(得分:1)

像这样的微观基准本质上是有缺陷的,你永远不会得到使用它们的精确读数 - 特别是在纳秒范围内。 JIT需要时间来“热身”到您的代码,在此期间它将围绕调用的代码进行优化。

如果你必须沿着这条路走下去,那么你需要一个测试集,你的算法需要几秒才能运行而不是纳秒,最好是那里的“热身”时期。好吧 - 那么你可能会看到一些与你期望的差异接近的差异。你永远不会只是能够采用这些时间并直接计算它们的时间复杂度 - 你需要运行许多不同大小的情况,然后绘制一个图表来确定每个输入大小的时间。即使这种方法也不会获得出色的准确结果,但这足以给出一个想法。

答案 3 :(得分:1)

你的问题可能与Can a program calculate the complexity of an algorithm?Program/algorithm to find the time complexity of any given program有关,我认为你做的是一个程序,你可以计算或循环,看看它是否嵌套,但我不知道你是怎么做的可以计算一些递归函数的复杂度。

答案 4 :(得分:1)

您编写的微基准测试不正确。如果您想收集代码的一些时间指标以进行进一步优化,JFF等使用JMH。这对你有很大帮助。

答案 5 :(得分:1)

当我们说算法表现出O(nlogn)复杂度时,我们说该算法的渐近上界O(nlogn)。也就是说,对于足够大的n值,算法的行为类似于函数n log n。我们并不是说对于n输入,肯定会有n log n次执行。只是这是您的算法所属的定义集。

通过在系统上花费时间间隔,您实际上是在暴露自己对计算机系统中涉及的各种变量。也就是说,你正在处理系统延迟,线路电阻,CPU速度,RAM使用等等。所有这些都会对你的结果产生可测量的影响。这就是为什么我们使用asymptotics来计算算法的时间复杂度。

答案 6 :(得分:1)

检查时间复杂度的一种方法是在n的不同大小上运行两种算法,并检查每次运行之间的比率。从这个比例,你可以得到时间复杂度

例如
如果时间复杂度为O(n),则比率将为线性

如果时间复杂度为O(n^2),则比率为(n1/n2)^2 如果时间复杂度为O(log(n)),则比率为log(n1)/log(n2)