简体   繁体   English

为什么这个阶乘查找算法的运行时复杂度不是 O(n!)?

[英]Why isn't this factorial finding algorithm O(n!) run-time complexity?

I discovered this issue by implemented the algorithm from this post: Example of O(n!)?我通过实现这篇文章中的算法发现了这个问题: O(n!) 的例子?

I tried counting the operations though, and the algorithm loops 64 times when calculating 4!不过,我尝试对操作进行计数,计算 4 时,算法循环了 64 次! (which is 24). (这是 24)。

Is there something I'm missing?有什么我想念的吗? Or does this algorithm really just have a run-time complexity that is not O(n!)或者这个算法真的只是有一个不是 O(n!) 的运行时复杂度吗?

 var operations = 0; function factorial(n) { for (let i = 0; i < n; i++) { operations++; factorial(n - 1); } } console.log(factorial(4)) console.log('operations: ', operations) // prints 64 operations

There is probably a good theoretical analysis, but here is an empirical one.可能有一个很好的理论分析,但这里是一个经验分析。 在表格中乱搞 I ran the program for numbers 0 to 12 and tracked operations.我运行了数字 0 到 12 的程序并跟踪了操作。 Notice that very quickly the operations tend to be really close to n times the previous entry.请注意,操作很快就会非常接近前一个条目的 n 倍。 And the ratio of operations to n!以及操作数与 n 的比率! appears to tend to e.似乎倾向于 e。 Thus, if the limit of operations is e (or some constant) times n!, we are O(n!).因此,如果操作的限制是 e(或某个常数)乘以 n!,我们是 O(n!)。 We need not = n!我们不需要= n! to make that so.做到这一点。

You're counting loop operations on every recursion level (ie counting function calls except for the outermost one), instead of counting the innermost function calls.您在每个递归级别计算循环操作(即计算除最外层的函数调用),而不是计算最内层的函数调用。 Therefore you're getting a much higher count than the plain factorial you were expecting:因此,您得到的计数比您期望的普通阶乘要高得多:

1                         = 1
2 + 2*1                   = 4
3 + 3*2 + 3*2*1           = 15
4 + 4*3 + 4*3*2 + 4*3*2*1 = 64
…

The expansions for arbitrary n can be found in https://oeis.org/A007526 .任意n的扩展可以在https://oeis.org/A007526 中找到。 These are still limited by O(n!) though - see the closed formulas in the link, eg floor(e*n! - 1) or n! * Sum_{k=0..n-1} 1/k!这些仍然受到O(n!)限制- 请参阅链接中的封闭公式,例如floor(e*n! - 1)n! * Sum_{k=0..n-1} 1/k! n! * Sum_{k=0..n-1} 1/k! , which are clearly dominated by the n! ,这显然是由n! term.学期。 (Counting all invocations gives you https://oeis.org/A000522 , n! * Sum_{k=0..n} 1/k! ). (计算所有调用给你https://oeis.org/A000522 , n! * Sum_{k=0..n} 1/k! )。

To get exactly a factorial, you'd need to count only the innermost function calls:要获得精确的阶乘,您只需要计算最内部的函数调用:

 var operations = 0; function factorial(n) { if (n == 0) operations++; for (let i = 0; i < n; i++) { factorial(n - 1); } } console.log(factorial(4)) console.log('operations: ', operations) // prints 64 operations

The factorial function should be:阶乘函数应该是:

var operations = 0;

function factorial(n) {
    operation++;
    if (n === 0) return 1;
    return n*factorial(n - 1);
}

console.log(factorial(4))
console.log('operations: ', operations) // prints 24 operations

And it's O(n).它是 O(n)。 The example is about O(n!), which is a time complexity depend on n!, not n!这个例子是关于 O(n!),它的时间复杂度取决于 n!,而不是 n! itself.本身。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM