【问题标题】:StackOverFlowError in java program [duplicate]java程序中的StackOverFlowError [重复]
【发布时间】:2014-11-16 05:29:30
【问题描述】:

我正在尝试解决一个问题,该问题要求找到最小的素数回文数,它出现在给定数字之后,这意味着如果输入是 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);
            }
        }
    }
}

【问题讨论】:

    标签: java recursion stack-overflow


    【解决方案1】:

    所有显示的现有解决方案都使用递归,并且存在一个问题,即在某些时候它们会到达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;
        }
    }
    

    【讨论】:

    • 我的没有递归:/
    • 对不起,我没有仔细阅读;-)
    【解决方案2】:

    在每次递归调用中都会创建一个新的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());
        }
    }
    

    【讨论】:

    • 谢谢你我明白你在说什么。我忍不住要问另一个问题。这个堆栈的大小是依赖于机器还是依赖于语言,还是两者都没有?
    • 它依赖于机器和语言。有关不同 jvm 在 java 中的默认堆栈大小,请参阅这篇文章stackoverflow.com/questions/6020619/…
    【解决方案3】:

    您应该知道的第一件事是您的资源是有限的。即使您的实现是精确的并且所有递归调用都是正确的,您仍然可能会收到错误。该错误表明您的 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;
    }
    }
    

    【讨论】:

      猜你喜欢
      • 2011-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-26
      • 1970-01-01
      • 2017-09-05
      • 2014-10-09
      相关资源
      最近更新 更多