代码为123456789提供java.lang.StackOverflowError但不为9999999999999999999提供

时间:2014-01-13 22:01:50

标签: java recursion stack-overflow

所以我正在做这个练习,只使用String类找到下一个回文。

我有点解决了,但对某事有疑问。

当我输入像123456789这样的字符串时,我得到一个java.lang.StackOverflowError。 当我输入更大的字符串,如9999999999999999999时,我不会得到错误。 我在这个网站做了一些研究,我认为它与我使用的递归回文方法有关。

有什么方法可以改进我的代码,以便处理更大的数字?为什么123456789会出错并且9999999999999999999不会?后者更大。

import java.io.*;

public class mainclass {

public static void main(String[] args) throws IOException {
    InputStreamReader isr = new InputStreamReader(System.in);
    BufferedReader in = new BufferedReader(isr);
    System.out.println(palindroom(in.readLine()));
    }

public static String increment(String str){
    String incre="";
    if(str.equals("9")){incre = "10";}
    else{
        switch(str.charAt(str.length()-1)){
        case '0': incre = str.substring(0, str.length()-1)+"1";break;
        case '1': incre = str.substring(0, str.length()-1)+"2";break;
        case '2': incre = str.substring(0, str.length()-1)+"3";break;
        case '3': incre = str.substring(0, str.length()-1)+"4";break;
        case '4': incre = str.substring(0, str.length()-1)+"5";break;
        case '5': incre = str.substring(0, str.length()-1)+"6";break;
        case '6': incre = str.substring(0, str.length()-1)+"7";break;
        case '7': incre = str.substring(0, str.length()-1)+"8";break;
        case '8': incre = str.substring(0, str.length()-1)+"9";break;
        case '9': incre = increment(str.substring(0, str.length()-1))+"0";break;
        };
        }
    return incre;
    }

public static String palindroom(String str){
    String palin=increment(str);
    boolean isPalindroom=true;
    for(int i=0;i<palin.length();i++){
        if(palin.charAt(i)==palin.charAt(palin.length()-i-1)){}
        else{isPalindroom=false;}
    }
    if(isPalindroom){return palin;}
    else{return palindroom(increment(str));}
}
}

3 个答案:

答案 0 :(得分:4)

因为只有在输入的值不是回文值时递归,并且需要超过10,000次递归才能将123456789递增到回文中。

你的代码有点奇怪,你拿一个字符串,你假设它是一个数字,并使用字符串操作递增它。转换为long(如果Long不够大,则转换为BigInteger)会更简单。

此外,您似乎增加了两次,一次是palindroom方法的开头,另一次是else块。

<强>更新 从你的评论中,我认为你可能不清楚Stack Overflow Error是什么。因此java调用堆栈是方法的堆栈(即LIFO)。在你的情况下,你的调用栈将是main,palindroom,palindroom,palindroom,palindroom,palindroom等...请注意java只允许调用堆栈的最大大小,如果超过此大小,则会出现堆栈溢出异常。 Java stack overflow error - how to increase the stack size in Eclipse?有一些关于默认值和配置的详细信息。

答案 1 :(得分:0)

我知道你对如何用循环替换你的递归方法有疑问,我已经编写了这个用于练习,所以你可以检查出来:

  public static void main(String[] args) throws IOException {
    InputStreamReader isr = new InputStreamReader(System.in);
    BufferedReader in = new BufferedReader(isr);

    String numString = in.readLine();
    BigInteger num = new BigInteger(numString);
    do {
      num = num.add(new BigInteger("1"));
    } while(pal(num));

    System.out.println(num);
  }

  public static boolean pal(BigInteger num){
    String isPal = num.toString();
    boolean isPalindroom=false;

    for(int ii=0; ii<isPal.length(); ii++){
      if(isPal.charAt(ii) != isPal.charAt(isPal.length()-ii-1))
        isPalindroom = true;
    }

    return isPalindroom;
  }

答案 2 :(得分:0)

仅作为函数的最后一步发生的递归 - 所谓的“尾递归” - 通常是伪装的循环;你只是用一组新参数重复函数的主体。一个好的优化器通常会将尾递归重写为循环;显然Java并不在你的情况下。

此示例的简单迭代重写示例:

public static String palindroom(String str){
  while(true)
  {
    String palin=increment(str);
    boolean isPalindroom=true;
    for(int i=0;i<palin.length();i++){
        if(palin.charAt(i)==palin.charAt(palin.length()-i-1)){}
        else{isPalindroom=false;}
    }
    if(isPalindroom){return palin;}
    else{str=palin;} //increment str, and try again
  }
}

这不会解决您的逻辑问题 - 请参阅其他响应 - 但它完全在单个堆栈框架内运行。