如何绕过递归堆栈溢出?

时间:2014-10-18 01:23:55

标签: java recursion stack-overflow

编辑:只是为了澄清,递归是作为作业的一部分所必需的,因此即使我知道这不是解决此问题的最佳方式,也必须递归

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

这适用于小字典,但我刚刚发现,对于一定数量的字典,递归有一个堆栈限制,所以我得到一个堆栈溢出错误。

我的想法是将每次递归限制为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;
    }

和前缀方法:

  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;
     }

编辑以澄清:

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

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

如果程序正在通过它,任何前两个字母的字母都不匹配,程序将移动到下一个给定的单词。

1 个答案:

答案 0 :(得分:0)

这实际上是一个很好的任务。让我们做一些假设....

  1. 字母表中有26个字母,所有单词都在这些字母中。
  2. 没有一个单词超过......大约1000个字符。
  3. 创建一个类,将其命名为“Node&#39;”,如下所示:

    private static class Node {
        Node[] children = new Node[26];
        boolean isWord = false;
    }
    

    现在,使用此节点类创建一个树。这棵树的根是:

    private final Node root = new Node ();
    

    然后,字典中的第一个单词是&#39; a&#39;。我们将它添加到树中。请注意&#39; a&#39;是字母0。

    所以,我们推算&#39;在树上:

    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;
    

    所以,你可以创建一个单词树......现在,如果你需要找到以给定字母序列(prefix)开头的所有单词,你可以这样做:

    Node wordNode = getNodeForChars(root, prefix.toCharArray(), 0);
    

    现在,如果isWord为true,则此节点及其所有非null且isWord为true的子节点都是带前缀的单词。你只需要重建序列。您可能会发现将实际单词存储为Node的一部分是有利的,而不是布尔isWord标志。你的电话。

    递归深度永远不会超过最长的单词。数据的密度被散开了&#39;很多。设置节点的其他方法可能在性能或空间方面更高(或更低)。但是,您的想法是在宽树中设置数据,因此搜索速度非常快,并且任何点上的所有子节点都具有与父节点相同的前缀(或者更确切地说,父节点是前缀)