【问题标题】:Factorial method - recursive or iterative? (Java)阶乘法——递归还是迭代? (爪哇)
【发布时间】:2012-06-25 15:56:53
【问题描述】:

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

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;
        }

和递归:

public static long factorial(int num) {
        if(num == 0) {
            return 1;
        }
        else {
            return num * factorial(num - 1);
        }
    }

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

【问题讨论】:

  • @luketorjussen - 因为我处理的数字很少,而且由于我只调用该方法一两次,我不会注意到差异。我在说的是,如果我使用这种方法会加载和加载多次,或者是可以使用这两种技术的更复杂的方法。
  • 你为什么不同时尝试一下,看看哪个更快?你也不需要去检查如果num == 0,如果num == 1那么你可以返回1,为什么要额外的迭代/函数调用
  • @Bluefire,那么为什么不尝试使用大数字并多次调用它呢?
  • 迭代版本似乎过于复杂。可以简化为int res = 1; for (int i = 2; i &lt;= num; ++i) res *= i; return res;

标签: java recursion iteration


【解决方案1】:

两者都是无可救药的天真。任何一个严重的阶乘应用都不会使用。我认为两者对于大 n 来说都是低效的,当参数很大时,intlong 都不够。

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

Here's Robert Sedgewick 的实现。

较大的值需要对数。

【讨论】:

  • 我认为编辑后会更好:) 撤回我之前的评论
【解决方案2】:

每当您可以在递归和迭代之间进行选择时,请始终选择迭代,因为

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

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

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

【讨论】:

  • 创建和销毁堆栈帧的成本并不高。像这样的尾递归可以被语言处理器优化掉。递归通常是表达计算的一种更自然的方式,而且成本可以忽略不计。
【解决方案3】:

这个问题没有“这更好,那更糟”。因为现代计算机非常强大,所以在 Java 中,它往往是您使用的个人偏好。您在迭代版本中进行了更多检查和计算,但是在递归版本中您将更多方法堆积到堆栈中。各有优劣,所以你必须逐案处理。

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

【讨论】:

  • 您没有在迭代版本中进行更多检查或计算。
  • @NiklasB。如果我的计数是正确的,他正在检查迭代版本中的起始num == 0i &lt;= numi++result *= i,而在递归版本中,他有num == 0num * factorial(num - 1),一半为很多。
  • 哦,你说的是代码复杂度。在那种情况下,我同意。我虽然您在谈论运行时复杂性(因为毕竟,在两个版本中将执行相同数量的乘法)。
【解决方案4】:

我实际上是按时间因素分析这个问题。 我做了两个简单的实现:

迭代:

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 上的递归解决方案更快。 (还是只谈时间)

如果你感兴趣,我得到这个结论的整个方法是HERE

如果您有兴趣更深入地了解这两种方法之间的区别,我在knowledge-cess.com 上找到了非常好的描述

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-08-17
    • 1970-01-01
    • 2011-09-21
    • 2015-04-20
    • 2011-05-23
    • 2014-03-24
    相关资源
    最近更新 更多