我只是在理论上读过关于时间的复杂性..有没有办法在程序中计算它们?不是像'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()
不够精确还是我应该使用较慢的系统?或者还有其他方法吗?
答案 0 :(得分:4)
有没有办法在程序中计算它们?不是像'n'或其他任何假设,而是通过实际值。
我认为你误解了复杂性是什么。这不是一个价值。它甚至不是一系列价值观。这是一个公式。如果你摆脱N
它作为复杂性度量是没有意义的(除了O(1)
......显然)。
一方面设置该问题,理论上可以自动化对复杂性的严格分析。然而,这是一个难题:自动化定理证明是困难的......特别是如果循环中没有人来“指导”这个过程。 Halting定理意味着不能有一个能够证明任意程序复杂性的自动定理证明器。 (当然,没有一个复杂性证明器适用于可能会或可能不会终止的所有程序...)
但是有一种方法可以计算具有给定输入集的程序的性能度量。你跑吧!事实上,你会进行一系列的运行,根据某些问题规模度量(即N
)来绘制表现图......并对与绩效和N
度量相关的公式进行有根据的猜测。或者您可以尝试将测量值拟合到公式中。
然而......
例如,如果您在经典Quicksort上尝试此操作,您很可能会认为复杂性为O(NlogN)
,并且错过了一个重要的警告:“最坏情况”是O(N^2)
。另一个例子是当问题规模变大时,可观察的性能特征改变。
简而言之,这种方法很可能会给你不可靠的答案。
答案 1 :(得分:2)
嗯,在实践中对程序有一些假设,你可能能够在大量测试用例上运行你的程序(并测量它花费的时间)并使用插值来估计程序的增长率和复杂性,并使用statistical hypothesis testing来显示您的正确概率。
然而,在所有情况下都无法做到这一点。事实上,你甚至不能有一个算法告诉每个程序它是否要暂停(运行一个无限循环)。这被称为Halting Problem,它被证明是可以解决的。
答案 2 :(得分:1)
如果你必须沿着这条路走下去,那么你需要一个大测试集,你的算法需要几秒才能运行而不是纳秒,最好是那里的“热身”时期。好吧 - 那么你可能会看到一些与你期望的差异接近的差异。你永远不会只是能够采用这些时间并直接计算它们的时间复杂度 - 你需要运行许多不同大小的情况,然后绘制一个图表来确定每个输入大小的时间。即使这种方法也不会获得出色的准确结果,但这足以给出一个想法。
答案 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)