java程序中的StackOverFlowError

时间:2014-11-16 05:29:30

标签: java recursion stack-overflow

我正在尝试解决一个问题,要求找到最小的主要回文,这是在一个给定的数字之后,这意味着如果输入为24,则输出为101,因为它是24之后的最小数字,这两者都是素数和回文。

现在我的代码完全适用于小值但是当我插入像543212这样的东西作为输入时,我最终得到第20行的StackOverFlowError,然后是第24行的StackOverFlowErrors的多个实例。这是我的代码:

package nisarg;
import java.util.Scanner;

public class Chef_prime_palindromes {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        long num = input.nextLong();
        isPalindrome(num + 1);
    }

    public static boolean isPrime(long num) {
        long i;
        for (i = 2; i < num; i++) {
            if (num % i == 0) {
                return false;
            }
        }
        return true;
    }

    public static void isPalindrome(long num) {
        String word = Long.toString(num);
        int i;
        for (i = 0; i < word.length() / 2; i++) {
            if (word.charAt(i) != word.charAt(word.length() - i - 1)) {
                isPalindrome(num + 1);
            }
        }
        if (i == word.length() / 2) {
            if (isPrime(num)) {
                System.out.println(num);
                System.exit(0);
            } else {
                isPalindrome(num + 1);
            }
        }
    }
}

3 个答案:

答案 0 :(得分:2)

所有显示的现有解决方案都使用递归,并且存在这样的问题:在某些时候它们将达到StackOverflowException将发生的点。 一个可并行化的更好的解决方案是将其改为循环。

可能是这样的:

package nisarg;

import java.math.BigInteger;
import java.util.Scanner;
import java.util.concurrent.CopyOnWriteArrayList;


public class Chef_prime_palindromes {
    private static  final CopyOnWriteArrayList<BigInteger> PRIMESCACHE 
        = new CopyOnWriteArrayList<>();


    public static void main(String[] args) {
        try (Scanner input = new Scanner(System.in)) {
            BigInteger num = new BigInteger(input.nextLine());

            initPrimes(num);

            for (num = num.add(BigInteger.ONE);
                    !isPrimePalindrome(num); 
                    num = num.add(BigInteger.ONE)); 

            System.out.println(num.toString());
            }
    }

    private static void initPrimes(BigInteger upTo) {
        BigInteger i;
        for (i = new BigInteger("2"); i.compareTo(upTo) <= 0 ; i = i.add(BigInteger.ONE)) {
            isPrime(i);
        }
    }


    public static boolean isPrimePalindrome(BigInteger num) {
        return isPrime(num) && isPalindrome(num);
    }

    // could be optimized
    public static boolean isPrime(BigInteger num) {

        for (int idx = PRIMESCACHE.size() - 1; idx >= 0; --idx) {
            if (num.mod(PRIMESCACHE.get(idx)).compareTo(BigInteger.ZERO) == 0) {
                return false;
            }   
        }

        if (!PRIMESCACHE.contains(num)) {
            PRIMESCACHE.add(num);
        }
        return true;
    }

    public static boolean isPalindrome(BigInteger num) {
        String word = num.toString();
        int i;
        for (i = 0; i < word.length() / 2; i++) {
            if (word.charAt(i) != word.charAt(word.length() - i - 1)) {
                return false;
            }
        }
        return true;
    }
}

答案 1 :(得分:1)

在每个递归调用中创建一个新的String object并放置到堆栈(存储方法中创建的所有变量的位置,直到您离开该方法),这对于足够深的递归使得JVM到达结束时分配堆栈空间。

我通过将String对象放置在一个单独的方法中来改变它的局部性,从而减少其局部性并将其创建和销毁(释放堆栈空间)限制为一个递归调用。

package com.company;

import java.util.Scanner;

public class Chef_prime_palindromes {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        long num = input.nextLong();
        isPalindrom(num + 1);
    }

    public static boolean isPrime(long num) {
        long i;
        for (i = 2; i < num; i++) {
            if (num % i == 0) {
                return false;
            }
        }
        return true;
    }

    private static void isPalindrom(long num) {
        for (; ; ) {
            if (isPalindrome(num)) {
                if (isPrime(num)) {
                    System.out.println(num);
                    System.exit(0);
                } else {
                    num++;
                }
            } else {
                num++;
            }
        }
    }

    public static boolean isPalindrome(long num) {
        String string = String.valueOf(num);
        return string.equals(new StringBuilder(string).reverse().toString());
    }
}

答案 2 :(得分:1)

您应该注意的第一件事是您的资源有限。即使您的实现是精确的并且所有递归调用都是正确的,您仍可能会收到错误。该错误表明您的JVM堆栈空间不足。尝试增加JVM堆栈的大小(有关详细信息,请参阅here)。

另一个重要的事情是寻找素数和回文数的分布。您的代码通过针对回文属性测试每个num+1来运行。这是不正确的。当数字为素数时,您只测试回文 。这将使计算更容易(并减少递归调用)。我已相应地编辑了您的代码,并在543212(1003001)之后获得了最接近的回文数。这是:

    public static void main(String[] args) {

     Scanner input = new Scanner(System.in);
    long num = input.nextLong();
    //isPalindrome(num+1);
    nextPrimePalindrome(num+1);
    }

    public static void nextPrimePalindrome(long num)
    {
        boolean flag=true;
        while(flag)
        {
            if(isPrime(num))
                if(isPalindrome(num))
                {
                    System.out.println(num);
                    flag=false;
                }
              num++;      
        }
    }

public static boolean isPrime(long num){
    long i;
    for(i=2;i<num;i++){
        if(num%i == 0){
            return false;
        }
    }
    return true;
}

public static boolean isPalindrome(long num)
{
    String word=Long.toString(num);
    for(int i=0;i<word.length()/2;i++)
        if(word.charAt(i)!=word.charAt(word.length()-i-1))
            return false;
    return true;
}
}