程序可以计算算法的复杂度吗?
有没有办法以编程方式计算算法的时间复杂度?例如,如何计算 fibonacci(n)
函数的复杂度?
Is there any way to compute the time complexity of an algorithm programatically? For example, how could I calculate the complexity of a fibonacci(n)
function?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
停止问题的不确定性表明您甚至无法判断算法是否终止。我非常确定,您通常无法解决算法的复杂性。
The undecidability of the halting problem says that you can't even tell if an algorithm terminates. I'm pretty sure from this it follows that you can't generally solve the complexity of an algorithm.
虽然不可能对所有情况都这样做(除非您运行自己的代码解析器并只查看循环以及对其值的影响等),但仍然可以使用上限时间集进行黑盒测试。也就是说,设置一些变量来确定一旦程序的执行经过这个时间,它就被认为是永远运行的。
从这里你的代码看起来与此类似(快速而肮脏的代码抱歉它有点冗长,并且对于我没有检查过的更大的权力,数学可能会关闭)。
可以通过使用输入值的集合数组而不是随机生成一些值来改进它,并且通过检查更广泛的值,您应该能够检查任何输入与任何其他两个输入,并确定方法持续时间的所有模式。
我确信有比这里显示的更好(即更准确)的方法来计算一组给定数字之间的 O 方法(它忽略了过多地关联元素之间的运行时间)。
和一个示例输出:
这表明对于给定输入 +/- 2% 方差,魔术方法可能是
O(N^2)
以及另一个结果:
这表明魔术方法可能是
O(N^3)
对于给定的输入 +/- 2% 方差因此,可以通过编程方式确定算法的复杂性,您需要确保不会引入一些额外的工作,从而导致算法比你想象的要长(例如在你之前构建函数的所有输入开始计时)。
除此之外,您还需要记住,这将花费大量时间来尝试大量可能的值并返回所花费的时间,更现实的测试是仅以较大的实际上限值调用您的函数,并且确定其响应时间是否足以满足您的使用。
如果您在没有源代码的情况下执行黑盒测试(并且无法使用 Reflector 等工具查看源代码),或者您必须向 PHB 证明编码算法的速度与正如您所说,它可以是(忽略对常量的改进)。
While it's impossible to do for all cases (unless you run your own code parser and just look at loops and what impacts on their values and such), it is still possible to do as a black box test with an upper bound time set. That is to say, have some variable that is set to determine that once a program's execution passes this time it's considered to be running forever.
From this your code would look similar to this (quick and dirty code sorry it's a little verbose and the math might be off for larger powers I haven't checked).
It can be improved upon by using a set array of input values rather than randomly generating some, and also by checking a wider range of values, you should be able to check any input versus any other two inputs and determine all the patterns of method duration.
I'm sure there are much better (namely more accurate) ways to calculate the
O
between a set of given numbers than shown here (which neglects to relate the run time between elements too much).And an example output:
Which shows the magic method is likely
O(N^2)
for the given inputs +/- 2% varianceand another result here:
Which shows the magic method is likely
O(N^3)
for the given inputs +/- 2% varianceSo It is possible to programatically determine the complexity of an algorithm, you need to make sure that you do not introduce some additional work which causes it to be longer than you think (such as building all the input for the function before you start timing it).
Further to this you also need to remember that this is going to take a significant time to try a large series of possible values and return how long it took, a more realistic test is to just call your function at a large realistic upper bound value and determine if it's response time is sufficient for your usage.
You likely would only need to do this if you are performing black box testing without source code (and can't use something like Reflector to view the source), or if you have to prove to a PHB that the coded algorithms are as fast as it can be (ignoring improvements to constants), as you claim it is.
不是一般情况下。例如,如果算法由嵌套的简单
for
循环组成,那么您就知道这将贡献
(ba)
步骤。现在,如果b
或a
或两者都依赖于n
,那么您可以从中获得复杂性。但是,如果您有一些更奇特的东西,那么您确实需要了解
whackyFunction(i)
的作用。类似地,break 语句可能会搞砸,而 while 语句可能会失败,因为您甚至可能无法判断循环是否终止。
Not in general. If the algorithm consists of nested simple
for
loops, e.g.then you know this will contribute
(b-a)
steps. Now, if eitherb
ora
or both depends onn
, then you can get a complexity from that. However, if you have something more exotic, likethen you really need to understand what
whackyFunction(i)
does.Similarly,
break
statements may screw this up, andwhile
statements may be a lost cause since it's possible you wouldn't even be able to tell if the loop terminated.计算 fibbonacci() 或其他任何内容中使用的算术运算、内存访问和内存空间,测量其执行时间。使用不同的输入来执行此操作,查看新兴趋势和渐近行为。
Count arithmetic operations, memory accesses and memory space used inside
fibbonacci()
or whatever it is, measure its execution time. Do this with different inputs, see the emerging trends, the asymptotic behavior.像圈复杂度这样的一般度量有助于让您了解代码中更复杂的部分,但这是一个相对简单的机制。
General measures like cyclomatic complexity are useful in giving you an idea of the more complex portions of your code, but it is a relatively simple mechanism.