递归阶乘是非常快的

时间:2016-09-23 20:34:09

标签: c# recursion factorial

由于高问题复杂性,因子的递归计算应该很慢。 为什么我的基本实现不是很慢?我很好奇,因为这应该是一个糟糕方法的教科书例子。

是否因为某些内部优化或缓存会导致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)

3 个答案:

答案 0 :(得分:3)

因子计算中的递归方法被认为是错误的,因为堆栈内存消耗而不是因为速度。

如果你拿一个足够大的数字,你会很快耗尽内存来计算因子,而不是你会慢一点(假设存储器存储 factorial ed 值足以存储它。)

答案 1 :(得分:2)

使用递归和迭代的阶乘函数的时间复杂度是相同的,尽管递归使用额外的内存空间来存储堆栈中的函数调用。但是,就时间复杂度而言,它是在这种情况下也是如此,因为递归间接地作为一个循环。递归的时间 - 复杂性变得比它的迭代对应物更糟,当递归试图反复计算相同的值时,这在迭代中被避免。例如:使用没有记忆的递归的Fibonacci数字具有O(2 ^ n)最坏情况时间复杂度,而它的迭代对应物具有O(n)最坏情况时间复杂度。

答案 2 :(得分:0)

JIT有可能正在使用尾递归优化,这有助于加快速度,see this for more information。如果没有访问您的环境,很难肯定地说。

给定的方法被认为是不利的方法,因为它使用大量的堆栈内存来处理更大的因子。它与速度关系不大,更多地与它消耗的内存有关。但是,如果你知道尾部递归会在那里发生(由JIT决定,不是由你决定,所以不要指望它),它确实无关紧要。