Java 如何避免递归堆栈溢出?
编辑:只是澄清一下,递归是赋值的一部分,因此它必须是递归的,尽管我知道这不是解决这个问题的最佳方法 我制作了一个程序,在某种程度上,它将搜索一个非常大的字典,并将给定的单词列表与字典中的每个单词进行比较,然后返回一个以用户给定单词的相同两个字母开头的单词列表 这适用于小型字典,但我刚刚发现对于超过一定数量的字典,递归有一个堆栈限制,因此我得到了一个堆栈溢出错误 我的想法是将每个递归限制为1000个递归,然后将一个计数器再增加1000个,然后从递归方法上次停止的地方重新开始,然后在2000年再次结束,然后依此类推,直到字典结束 这是最好的方法吗?如果是的话,有人知道怎么做吗?我真的很难实现这个想法 (编辑:如果这不是最好的方法,有人知道如何更有效地进行吗?) 这是我到目前为止的代码,这里几乎没有实现1000个递归的想法,因为我已经删除了我过去尝试过的一些代码,但老实说,它和我这里的代码一样有用 电话:Java 如何避免递归堆栈溢出?,java,recursion,stack-overflow,Java,Recursion,Stack Overflow,编辑:只是澄清一下,递归是赋值的一部分,因此它必须是递归的,尽管我知道这不是解决这个问题的最佳方法 我制作了一个程序,在某种程度上,它将搜索一个非常大的字典,并将给定的单词列表与字典中的每个单词进行比较,然后返回一个以用户给定单词的相同两个字母开头的单词列表 这适用于小型字典,但我刚刚发现对于超过一定数量的字典,递归有一个堆栈限制,因此我得到了一个堆栈溢出错误 我的想法是将每个递归限制为1000个递归,然后将一个计数器再增加1000个,然后从递归方法上次停止的地方重新开始,然后在2000年再次结
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个字符之间的字符串,只有字母没有空格等。程序创建一个该字符串所有可能排列的列表,然后遍历这些排列的数组,对于每个排列,返回另一个以给定单词的前两个字母开头的单词列表
如果在程序运行过程中,前两个字母之前的任何字母都不匹配,则程序将转到下一个给定的单词 这实际上是一个很好的作业。让我们做一些假设
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),而不仅仅是二进制搜索(这会起作用)。我在维基百科上添加了我之前评论的链接。