【问题标题】:Tail Recursion java尾递归java
【发布时间】:2014-10-01 11:15:00
【问题描述】:

我正在努力寻找任何给定数字的最大素数。下面的代码适用于大多数数字,直到我输入我想要的数字 600851475143。一旦我这样做,我就会得到堆栈溢出。我一直在阅读尾递归,据我所知,我应该正确实施它。然而,尽管如此,我仍然收到堆栈溢出错误。在实现尾递归时我哪里出错了?

import java.util.Scanner;
public class LargestPrimeFactor
{
    static long number;
    static long answer;

    public static void main(String[] args)
    {
        System.out.println( "Enter number to find its largest prime factor");
        Scanner input = new Scanner(System.in);
        number = input.nextLong();

        answer = largestPrime(number);
        System.out.println("The largest prime of " + number + " is " + answer);
    }

    private static long largestPrime(long n)
    {
        n = n-1;    
        if(n % 2 != 0 & number % n == 0 )
        {   
            return n;
        }
        else
        {           
            return largestPrime(n);
        }
    }
}

【问题讨论】:

  • 虽然 Java 确实支持尾递归调用,但我不认为它目前优化了它们。您可以考虑使用memoization
  • 你做的很好,但是你的java编译器没有把尾调用优化成一个循环

标签: java recursion stack-overflow tail-recursion


【解决方案1】:

首先,在 if 条件下,您正在执行 &,而您可能打算执行 &&。其次,您的实施不正确。尝试在 18 上运行它(最大的质数是 3),看看它返回的 9 显然不是质数。

至于 stackoverflow,由于在某些情况下没有限制 n > 1 的条件,因此计算将继续使用 -1, -2, -3,...,直到您获得 stackoverflow...

最后,JVM 支持尾递归优化,但即使支持 - 迭代解决方案几乎总是会更好,因为与递归解决方案不同 - 它不会打开每次递归调用都会在堆栈上创建一个新帧(因为没有递归调用 - 它在循环中运行)。

编辑

  • 要找到最大的素数,您可以从n/2 开始,然后往下走 (每次迭代减一)。
  • 素数p的定义是:p > 1p只能被自己分开(和1)。使用这个定义,写一个迭代方法boolean isPrime(int num)
  • 现在使用前两个要点并将它们结合起来编写一个递归方法来找到最大的素数。为了不破坏你的乐趣,我不想实现它:)

【讨论】:

  • 尾递归的关键不是旧的堆栈帧被新的堆栈帧覆盖吗?我可以看到它的效率较低,因为必须执行更多写入才能获得“干净”的帧(我不确定这是真的,我缺乏专业知识)。但说它“打开一个新框架”似乎不准确,除非它确实需要重置所有内容。
  • 是的,我正在运行一个迭代实现,但我注意到计算最终数字需要一段时间。这留下了两个问题。我在什么时候错误地实现了它,以至于它给出了不是素数的 9。另外,您有什么建议可以加快计算速度?
  • @ChrisHayes any 对方法的调用会在堆栈上打开一个新框架,即使经过优化,您也无法摆脱“push”和“pop”它需要。如果你想好好阅读这个主题:drdobbs.com/jvm/tail-call-optimization-and-java/240167044
  • @SEV19957 我将为此添加另一段。
  • @alfasin 是的,这正是我所需要的。我不太关心获得项目欧拉的数字。整个原因是通过创建它的过程来学习并推动自己去弄清楚。感谢您为我保存了有趣的实现部分:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-03-21
  • 2018-03-17
  • 1970-01-01
  • 2017-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多