Java 阶乘方法-递归还是迭代?(爪哇)

Java 阶乘方法-递归还是迭代?(爪哇),java,recursion,iteration,Java,Recursion,Iteration,我在通过Euler项目时遇到了一个组合问题。组合逻辑意味着计算阶乘。所以,我决定创建一个阶乘方法。然后我遇到了一个问题——因为我可以很容易地使用迭代和递归来实现这一点,我应该选择哪一个呢?我很快写了两种方法——迭代法: public static long factorial(int num) { long result = 1; if(num == 0) { return 1; } else {

我在通过Euler项目时遇到了一个组合问题。组合逻辑意味着计算阶乘。所以,我决定创建一个阶乘方法。然后我遇到了一个问题——因为我可以很容易地使用迭代和递归来实现这一点,我应该选择哪一个呢?我很快写了两种方法——迭代法:

public static long factorial(int num) {
        long result = 1;
        if(num == 0) {
            return 1;
        }
        else {
            for(int i = 2; i <= num; i++) {
                result *= i;
            }
            return result;
        }

如果我(显然)在这里谈论速度和功能,我应该使用哪一个?总的来说,这两种技术中的一种通常比另一种好(因此,如果我以后遇到这个选择,我应该选择什么)?

这两种技术都太天真了。阶乘的任何一种应用都不会使用这两种方法。我认为这两种方法对于较大的n都是无效的,并且当参数较大时,
int
long
都不能满足要求

更好的方法是使用良好的实现和记忆

Robert Sedgewick的一个实现


较大的值需要对数

每当您在递归和迭代之间选择一个选项时,总是选择迭代,因为

1.递归涉及创建和销毁堆栈帧,成本很高

2.如果使用的值非常大,堆栈可能会爆炸

所以,只有当你有一些非常诱人的理由时,才去递归

这个问题没有“这更好,那更糟”。因为现代计算机非常强大,所以在Java中,使用哪种计算机往往是个人的偏好。在迭代版本中,您要做更多的检查和计算,而在递归版本中,您要在堆栈上堆积更多的方法。各有利弊,所以你必须逐一考虑


就我个人而言,我坚持使用迭代算法来避免递归逻辑。

我实际上是通过时间因素来分析这个问题的。 我已经完成了两个简单的实现:

迭代:

private static BigInteger bigIterativeFactorial(int x) {
    BigInteger result = BigInteger.ONE;
    for (int i = x; i > 0; i--)
        result = result.multiply(BigInteger.valueOf(i));
    return result;
}
和递归:

public static BigInteger bigRecursiveFactorial(int x) {
    if (x == 0)
        return BigInteger.ONE;
    else
        return bigRecursiveFactorial(x - 1).multiply(BigInteger.valueOf(x));
}
测试都在单线程上运行。 事实证明,只有在参数很小的情况下,迭代的速度才稍微快一点。当我把n大于100时,递归解速度更快。 我的结论?在JVM上,您永远不能说迭代解决方案比递归解决方案快。(仍然只谈论时间)

如果你感兴趣的话,我得出这个结论的整个过程就是


如果您对深入理解这两种方法之间的差异感兴趣,我在@luketorjussen的

可能的副本上找到了非常好的描述-因为我处理的数字很低,而且由于我只调用该方法一两次,我不会注意到差异。我要说的是,如果我使用这种方法,会产生大量的时间,或者更复杂的方法,可以同时使用这两种技术。你为什么不试试这两种方法,看看哪种更快?另外,您不需要检查
num==0
,如果
num==1
,那么您可以返回1,为什么要执行额外的迭代/函数call@Bluefire,那么为什么不尝试使用大数字并多次调用它呢?迭代版本似乎过于复杂。它可以简化为
int res=1;对于(int i=2;i),在迭代版本中,您没有进行更多的检查或计算。@NiklasB。如果我的计数正确,他正在检查开始的
num==0
i哦,那么您是在谈论代码复杂性。在这种情况下,我同意。我以为您在谈论运行时复杂性(因为毕竟,在两个版本中执行相同数量的乘法)。我认为编辑后效果更好:)收回我之前的评论创建和销毁堆栈帧的成本并不高。语言处理器可以优化像这样的尾部递归。递归通常是表示计算的更自然的方式,并且成本可以很小。
public static BigInteger bigRecursiveFactorial(int x) {
    if (x == 0)
        return BigInteger.ONE;
    else
        return bigRecursiveFactorial(x - 1).multiply(BigInteger.valueOf(x));
}