【问题标题】:How to get around recursive stack overflow?如何解决递归堆栈溢出?
【发布时间】:2014-12-13 15:38:16
【问题描述】:

编辑:为了澄清,递归是作业的一部分,所以它必须是递归的,即使我知道这不是解决这个问题的最佳方法

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

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

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

编辑澄清:

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

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

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

【问题讨论】:

  • 递归是作业的一部分
  • 啊。在这种情况下,使用binary search 编写它。这会将深度从n 减少到lg(n) 并避免堆栈溢出。唯一的要求是对字典进行排序。由于匹配的字母可以“拆分”一个 i/2 分区,因此您需要考虑回退情况以找到第一个/最后一个单词也匹配。
  • 嗯好吧,我会研究二进制搜索,字典已排序
  • 谢谢!有没有机会你有很好的资源来实现二分搜索?
  • 此外,扇出可以用于每个字母(例如 a..z),而不仅仅是二进制(可以工作)。我添加了一个链接,指向我之前对 Wikipedia 的评论。

标签: java recursion stack-overflow


【解决方案1】:

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

  1. 字母表中有26个字母,所有单词都在这些字母中。
  2. 没有一个单词超过.... 1000 个左右的字符。

创建一个类,将其命名为“Node”,如下所示:

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;

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

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

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

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

【讨论】:

    猜你喜欢
    • 2022-01-05
    • 2015-04-04
    • 2017-01-20
    • 2018-12-02
    • 2017-09-06
    • 2019-07-08
    • 2015-08-05
    • 2017-09-29
    • 1970-01-01
    相关资源
    最近更新 更多