你如何编写一个非递归算法来计算 n!
?
你如何编写一个非递归算法来计算 n!
?
由于Int32在大于12!时会溢出,因此只需执行以下操作:
public int factorial(int n) {
int[] fact = {1, 1, 2, 6, 24, 120, 720, 5040, 40320,
362880, 3628800, 39916800, 479001600};
return fact[n];
}
伪代码中:
ans = 1
for i = n down to 2
ans = ans * i
next
为了科学研究的目的,我对计算阶乘的各种算法实现进行了一些分析。我使用C#和C++分别创建了迭代、查找表和递归实现,并将最大输入值限制在12或更小,因为13!大于2^32(32位整数能够容纳的最大值)。然后,我运行了每个函数1000万次,循环使用可能的输入值(即从0递增到1000万,使用i模13作为输入参数)。
这里是不同实现相对于迭代C++数据的相对运行时间:
C++ C#
---------------------
Iterative 1.0 1.6
Lookup .28 1.1
Recursive 2.4 2.6
为了完整起见,以下是使用64位整数并允许输入值高达20的实现的相对运行时间:
C++ C#
---------------------
Iterative 1.0 2.9
Lookup .16 .53
Recursive 1.9 3.9
public double factorial(int n) {
double result = 1;
for(double i = 2; i<=n; ++i) {
result *= i;
}
return result;
}
除非你有像Python一样的任意长度整数,否则我会将factorial()预计算值存储在大约20个长整型的数组中,并使用参数n作为索引。n!的增长速度相当高,即使在64位机器上计算20!或21!也会发生溢出。
这是预计算函数,但实际上是正确的。正如所说,13!会溢出,因此计算这么小的值范围没有意义。64位更大,但我认为范围仍然相当合理。
int factorial(int i) {
static int factorials[] = {1, 1, 2, 6, 24, 120, 720,
5040, 40320, 362880, 3628800, 39916800, 479001600};
if (i<0 || i>12) {
fprintf(stderr, "Factorial input out of range\n");
exit(EXIT_FAILURE); // You could also return an error code here
}
return factorials[i];
}
我喜欢这个Pythonic的解决方案:
def fact(n): return (reduce(lambda x, y: x * y, xrange(1, n+1)))
long fact(int n) {
long x = 1;
for(int i = 1; i <= n; i++) {
x *= i;
}
return x;
}
int total = 1
loop while n > 1
total = total * n
n--
end while