简体   繁体   English

Java递归中的堆栈溢出错误

[英]Stack overflow error in Java recursion

I'm trying to implement a code that returns the sum of all prime numbers under 2 million. 我正在尝试实现一个返回200万以下所有素数之和的代码。 I have an isPrime(int x) method that returns true if the the number is prime. 我有一个isPrime(int x)方法,如果数字是素数,则返回true。 Here it is: 这里是:

public static boolean isPrime(int x) {

        for (int i = 2; i < x; i++) {

            if (x % i == 0) {
                return false;
            }

        }
        return true;

    }

And the other method, which I'm trying to implement recursively, only works until a certain number, over that number and I get a stack overflow error. 另一种方法,我试图递归地实现,只有一定数量,超过该数字,我得到一个堆栈溢出错误。 The highest I got the code to work was for 10,000. 我得到的最高代码是10,000。

Here it is: 这里是:

public static int sumOfPrimes(int a) {

    if (a < 2000000) {  //this is the limit

        if (isPrime(a)) {
            return a + sumOfPrimes(a + 1);

        } else {
            return sumOfPrimes(a + 1);
        }

    }
    return -1;
}

So why do I get a stack overflow error when the number gets bigger and how can I deal with this? 那么为什么当数字变大时我会得到堆栈溢出错误,我该如何处理呢? Also, how do you normally deal with writing code for such big numbers? 另外,你通常如何处理为这么大的数字编写代码? IE: normal number operations like this but for larger numbers? IE:像这样的正常数字操作但是对于更大的数字? I wrote this recursively because I thought it would be more efficient but it still wont work. 我递归地写了这个,因为我认为它会更有效但它仍然无法工作。

Your isPrime function is inefficient, it doesn't have to go to x , it's enough to go to the square root of x. 你的isPrime函数是低效的,它不必转到x ,它足以转到x的平方根。

But that is not the reason why your solution doesn't work. 但这并不是您的解决方案不起作用的原因。 You cannot have a recursion depth of 1 million. 你不能有100万的递归深度。

I would solve this problem iteratively, using the sieve of eratosthenes and for loop over the resulting boolean array. 我会迭代地解决这个问题,使用eratosthenes筛子并在结果boolean数组上循环。

In general if you would still like to use recursion, you can use tail recursion. 通常,如果您仍想使用递归,则可以使用尾递归。 In recursion each function call will push some data to the stack, which is limited, thus generating a stackoverflow error. 在递归中,每个函数调用都会将一些数据推送到堆栈,这是有限的,因此会产生堆栈溢出错误。 In tail recursion you won't be pushing anything to the stack, thus not throwing the exception. 在尾递归中,你不会向堆栈推送任何东西,因此不会抛出异常。

Basically all you need is sending the data of the previous computation as parameter instead of having it on the stack. 基本上你只需要将先前计算的数据作为参数发送,而不是将它放在堆栈上。

So: 所以:

function(int x) {
    // end condition
    return function(x - 1) + x;
}

with tail recursion would be 尾部递归会

function (int max, int curr, int prev, int sum) {
    if (curr > max) 
        return sum;

    return function (max, curr + 1, curr, sum + curr)
}

Keep in mind this is just pseudo code not real java code, but is close enough to the java code. 请记住,这只是伪代码而不是真正的java代码,但与java代码足够接近。

For more info check 有关详细信息,请查看

What is tail recursion? 什么是尾递归?

Use Sieve of Eratosthenes:- 使用Eratosthenes筛选: -

Following is the algorithm to find all the prime numbers less than or equal to a given integer n by Eratosthenes' method: 以下是通过Eratosthenes方法找到小于或等于给定整数n的所有素数的算法:

1) Create a list of consecutive integers from 2 to n: (2, 3, 4, …, n). 1)创建从2到n的连续整数列表:(2,3,4,...,n)。
2) Initially, let p equal 2, the first prime number. 2)最初,让p等于2,即第一个素数。
3) Starting from p, count up in increments of p and mark each of these numbers greater than p itself in the list. 3)从p开始,以p为增量进行计数,并在列表中将每个数字标记为大于p本身。 These numbers will be 2p, 3p, 4p, etc.; 这些数字将是2p,3p,4p等; note that some of them may have already been marked. 请注意,其中一些可能已被标记。
4) Find the first number greater than p in the list that is not marked. 4)在列表中找到未标记的第一个大于p的数字。 If there was no such number, stop. 如果没有这样的号码,请停止。 Otherwise, let p now equal this number (which is the next prime), and repeat from step 3. 否则,让p现在等于这个数字(这是下一个素数),并从步骤3开始重复。

public static void main(String[] args) {
    int n = 30;
    System.out.printf("Following are the prime numbers below %d\n", n);
    SieveOfEratosthenes(n);
}

static void markMultiples(boolean arr[], int a, int n)
{
    int i = 2, num;
    while ( (num = i*a) <= n )
    {
        arr[ num-1 ] = true; // minus 1 because index starts from 0.
        ++i;
    }
}

// A function to print all prime numbers smaller than n
static void SieveOfEratosthenes(int n)
{
    // There are no prime numbers smaller than 2
    if (n >= 2)
    {
        // Create an array of size n and initialize all elements as 0
        boolean[] arr=new boolean[n];
        for(int index=0;index<arr.length-1;index++){
            arr[index]=false;
        }

        for (int i=1; i<n; ++i)
        {
            if ( arr[i] == false )
            {
                //(i+1) is prime, print it and mark its multiples
                System.out.printf("%d ", i+1);
                markMultiples(arr, i+1, n);
            }
        }
    }
}

Output:-
Following are the prime numbers below 30
2 3 5 7 11 13 17 19 23 29 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM