Java 如何避免递归堆栈溢出?

Java 如何避免递归堆栈溢出?,java,recursion,stack-overflow,Java,Recursion,Stack Overflow,编辑:只是澄清一下,递归是赋值的一部分,因此它必须是递归的,尽管我知道这不是解决这个问题的最佳方法 我制作了一个程序,在某种程度上,它将搜索一个非常大的字典,并将给定的单词列表与字典中的每个单词进行比较,然后返回一个以用户给定单词的相同两个字母开头的单词列表 这适用于小型字典,但我刚刚发现对于超过一定数量的字典,递归有一个堆栈限制,因此我得到了一个堆栈溢出错误 我的想法是将每个递归限制为1000个递归,然后将一个计数器再增加1000个,然后从递归方法上次停止的地方重新开始,然后在2000年再次结

编辑:只是澄清一下,递归是赋值的一部分,因此它必须是递归的,尽管我知道这不是解决这个问题的最佳方法

我制作了一个程序,在某种程度上,它将搜索一个非常大的字典,并将给定的单词列表与字典中的每个单词进行比较,然后返回一个以用户给定单词的相同两个字母开头的单词列表

这适用于小型字典,但我刚刚发现对于超过一定数量的字典,递归有一个堆栈限制,因此我得到了一个堆栈溢出错误

我的想法是将每个递归限制为1000个递归,然后将一个计数器再增加1000个,然后从递归方法上次停止的地方重新开始,然后在2000年再次结束,然后依此类推,直到字典结束

这是最好的方法吗?如果是的话,有人知道怎么做吗?我真的很难实现这个想法

编辑:如果这不是最好的方法,有人知道如何更有效地进行吗?)

这是我到目前为止的代码,这里几乎没有实现1000个递归的想法,因为我已经删除了我过去尝试过的一些代码,但老实说,它和我这里的代码一样有用

电话:

    for(int i = 0; i < givenWords.size(); i++){
        int thousand = 1000;
        Dictionary.prefix(givenWords.get(i), theDictionary, 0, thousand);
        thousand = thousand + 1000;
    }
for(int i=0;i
和前缀方法:

  public static void prefix (String origWord, List<String> theDictionary, int wordCounter, int thousand){

    if(wordCounter < thousand){ 
            // if the words don't match recurse through this same method in order to move on to the next word
        if (wordCounter < theDictionary.size()){   
          if ( origWord.charAt(0) != theDictionary.get(wordCounter).charAt(0) || origWord.length() != theDictionary.get(wordCounter).length()){
              prefix(origWord, theDictionary, wordCounter+1, thousand+1);

          }

          // if the words first letter and size match, send the word to prefixLetterChecker to check for the rest of the prefix.
          else{
              prefixLetterChecker(origWord, theDictionary.get(wordCounter), 1);
              prefix(origWord, theDictionary, wordCounter+1, thousand+1);
          }
        }
    }
    else return;
     }
publicstaticvoid前缀(stringorigword,列出字典,int字计数器,int千){
如果(字计数器<千){
//如果单词不匹配,则通过相同的方法递归,以便转到下一个单词
if(wordCounter
编辑澄清:

该词典是一个已排序的大词典,每行只有一个单词,小写

“给定单词”实际上是列表中的一个,在程序中,用户输入一个介于2-10个字符之间的字符串,只有字母没有空格等。程序创建一个该字符串所有可能排列的列表,然后遍历这些排列的数组,对于每个排列,返回另一个以给定单词的前两个字母开头的单词列表


如果在程序运行过程中,前两个字母之前的任何字母都不匹配,则程序将转到下一个给定的单词

这实际上是一个很好的作业。让我们做一些假设

  • 字母表中有26个字母,所有单词都在这些字母中
  • 没有一个词比。。。。大约1000个字符长
  • 创建一个类,称之为“节点”,类似于:

    private static class Node {
        Node[] children = new Node[26];
        boolean isWord = false;
    }
    
    现在,使用这个节点类创建一个树。此树的根是:

    private final Node root = new Node ();
    
    然后,词典中的第一个单词是“a”。我们把它添加到树上。请注意,“a”是字母0

    因此,我们“递归”到树中:

    private static final int indexOf(char c) {
        return c - 'a';
    }
    
    private final Node getNodeForChars(Node node, char[] chars, int pos) {
        if (pos == chars.length) {
            return this;
        }
        Node n = children[indexOf(chars[pos])];
        if (n == null) {
            n = new Node();
            children[indexOf(chars[pos])] = n;
        }
        return getNodeForChars(n, chars, pos + 1);
    }
    
    因此,有了它,您可以简单地执行以下操作:

    Node wordNode = getNodeForChars(root, word.toCharArray(), 0);
    wordNode.isWord = true;
    
    所以,你可以创建一个单词树。。。。。现在,如果您需要查找以给定字母序列开头的所有单词(前缀
    ),您可以执行以下操作:

    Node wordNode = getNodeForChars(root, prefix.toCharArray(), 0);
    
    现在,如果isWord为true,并且它的所有子节点都不为null且isWord为true,那么这个节点就是带有前缀的单词。你只需要重建序列。您可能会发现,将实际单词存储为节点的一部分,而不是布尔值isWord标志是有利的。你的电话


    递归深度永远不会超过最长的字。数据的密度被“分散”了很多。还有其他设置节点的方法,这些方法在性能或空间方面可能更高效(或更低)。不过,这个想法是,您可以在一个宽树中设置数据,因此搜索速度非常快,并且任何点上的所有子节点都具有与父节点相同的前缀(或者说,父节点是前缀)。

    递归是赋值AHH的一部分。在这种情况下,使用。这将把深度从
    n
    减少到
    lg(n)
    ,并避免堆栈溢出。唯一的要求是对字典进行排序。因为匹配的字母可以“拆分”i/2部分,所以您需要考虑倒排的情况,以找到同样匹配的第一个/最后一个单词。嗯,好的,我将研究二进制搜索,字典已分类谢谢!你有没有可能有很好的资源来实现二进制搜索?同样,扇出可以是每个字母(例如a..z),而不仅仅是二进制搜索(这会起作用)。我在维基百科上添加了我之前评论的链接。