由于高问题复杂性,因子的递归计算应该很慢。 为什么我的基本实现不是很慢?我很好奇,因为这应该是一个糟糕方法的教科书例子。
是否因为某些内部优化或缓存会导致C#程序?
using System;
using System.Diagnostics;
using System.Numerics;
namespace FactorialRecursion
{
class Program
{
static void Main(string[] args)
{
Stopwatch stopwatch = new Stopwatch();
for (int i = 0; i < 4000; i++)
{
stopwatch.Reset();
stopwatch.Start();
Factorial(i);
stopwatch.Stop();
Console.WriteLine($"{i}! = ({stopwatch.Elapsed})");
}
Console.ReadKey();
}
static BigInteger Factorial(BigInteger number)
{
if (number <= 1)
return 1;
return number * Factorial(number - 1);
}
}
}
结果如下:
3990! = (00:00:00.0144319)
3991! = (00:00:00.0149198)
3992! = (00:00:00.0159502)
3993! = (00:00:00.0116784)
3994! = (00:00:00.0104608)
3995! = (00:00:00.0122931)
3996! = (00:00:00.0128695)
3997! = (00:00:00.0131792)
3998! = (00:00:00.0142510)
3999! = (00:00:00.0145544)
答案 0 :(得分:3)
因子计算中的递归方法被认为是错误的,因为堆栈内存消耗而不是因为速度。
如果你拿一个足够大的数字,你会很快耗尽内存来计算因子,而不是你会慢一点(假设存储器存储 factorial ed 值足以存储它。)
答案 1 :(得分:2)
使用递归和迭代的阶乘函数的时间复杂度是相同的,尽管递归使用额外的内存空间来存储堆栈中的函数调用。但是,就时间复杂度而言,它是在这种情况下也是如此,因为递归间接地作为一个循环。递归的时间 - 复杂性变得比它的迭代对应物更糟,当递归试图反复计算相同的值时,这在迭代中被避免。例如:使用没有记忆的递归的Fibonacci数字具有O(2 ^ n)最坏情况时间复杂度,而它的迭代对应物具有O(n)最坏情况时间复杂度。
答案 2 :(得分:0)
JIT有可能正在使用尾递归优化,这有助于加快速度,see this for more information。如果没有访问您的环境,很难肯定地说。
给定的方法被认为是不利的方法,因为它使用大量的堆栈内存来处理更大的因子。它与速度关系不大,更多地与它消耗的内存有关。但是,如果你知道尾部递归会在那里发生(由JIT决定,不是由你决定,所以不要指望它),它确实无关紧要。