递归函数堆栈溢出

时间:2012-07-27 10:43:21

标签: visual-studio-2008 recursion stack-overflow backtracking

此函数采用包含'*'和'?'的字符串wild通配符,并使用nodeT *w从树数据库中替换带有可能字符的通配符。 out包含一个临时字符串。每个候选人都被添加到参考的bst。

void Lexicon::matchRegExpHelper(nodeT *w, string wild, Set<string> &matchSet, string out)
{   
    if (wild == "") matchSet.add(out);

    else {
        if (wild[0] != '*' || wild[0] != '?') { //this parses up to the wildcard, earlier versions used a position parameter and looped through the prefix chars recursively
            for (int j = 0; j < w->alpha.size(); j++)
                if (wild[0] == w->alpha[j].letter) matchRegExpHelper(w->alpha[j].next, wild.substr(1), matchSet, out+=wild[0]);
        } else {
            for (int i = 0; i < w->alpha.size(); i++) { 
                if (wild[0] == '?') matchRegExpHelper(w->alpha[i].next, wild.substr(1), matchSet, out+=w->alpha[i].letter);//follow path
                else { //logically, wild[0] == '*' must be true
                    if (ontLength == (wild.length() + out.length())) matchRegExpHelper(w->alpha[i].next, wild.substr(1), matchSet, out+=w->alpha[i].letter); //ontology is full, treat like a '?'
                    else matchRegExpHelper(w->alpha[i].next, wild.substr(1), matchSet, out+=(w->alpha[i].letter+'*')); //keep adding chars
                }
            }
        }
    }
}

当第一个通配符到达时,函数重新开始 - 我尝试用for循环重写它,没有循环,以及不同的'prune'方法。我遗漏了一些基本的东西,并怀疑这是一个回溯问题。最终堆栈溢出。

问题:1)我在概念上缺少什么,以及2)如何修复此功能?

没有for循环的

版本 - 测试用例有点不同但相似,我必须测试才能再找到它

else {
            if (wild[0] == '?'){
                matchRegExpHelper(w, wild, ++pos, matchSet, out);//return and check next path
                matchRegExpHelper(w->alpha[pos].next, wild.substr(1), 0, matchSet, out+=w->alpha[pos].letter);//follow path
            }
            if (wild[0] == '*'){
                matchRegExpHelper(w, wild, ++pos, matchSet, out);//return and check next path
                if (ontLength == (wild.length() + out.length()))matchRegExpHelper(w->alpha[pos].next, wild.substr(1), 0, matchSet, out+=w->alpha[pos].letter); //ontology is full, treat like a '?'
                else matchRegExpHelper(w->alpha[pos].next, wild.substr(1), 0, matchSet, out+=(w->alpha[pos].letter+'*')); //keep adding chars
            }
            if (wild[0] == w->alpha[pos].letter) matchRegExpHelper(w->alpha[pos].next, wild.substr(1), 0, matchSet, out+=wild[0]);  

            matchRegExpHelper(w, wild, ++pos, matchSet, out);//check next path
        }
        for (int i = 0; i < w->alpha.size(); i++) matchRegExpHelper(w->alpha[i].next, wild.substr(1), 0, matchSet, out+=wild[0]);//step over char

最后的for循环是尝试修复溢出,我想也许某些线程没有任何情况,但我希望那些修剪,所以不知道该怎么做

3 个答案:

答案 0 :(得分:2)

这种情况总是如此: (wild [0]!='*'|| wild [0]!='?')

因为任何一个角色都不同于两个中的一个,也许你的意思是(wild [0]!='*'&amp;&amp; wild [0]!='?')

我希望这有助于你取得一些进展......

从概念上讲,我通常不会在递归函数中使用'for',尝试重写它而不使用'for'可能它会更清晰,可能效率不高但是一旦它工作,你就可以开始微调算法了。

答案 1 :(得分:1)

每次递归都应该有一个基本终止条件。

我有种感觉

 if (wild[0] != '*' || wild[0] != '?') 

是错误的(该测试始终为真,因为某个字符不能同时为'*''?'),它应该是一个&&合取而不是一个分离{ {1}}

但正如我在评论中所说,你真的应该学习如何使用debugger (即提出breakpoints,要求backtraces,查询价值变量)。

熟悉调试是一项技能,除了这个特定的程序(或家庭作业)之外,对你的一生都有价值。

答案 2 :(得分:0)

此代码存在三个问题:

@Basile_Starynkevitch注意到使用调试器遵循路径的重要性 - 在这种情况下使用VS2008,堆栈允许解析步骤并注意通过几个函数返回的路径。

@Picarus正确地注意到终止条件中的错误

这些解决方案导致发现:

解决方案,这个void函数需要两个return;,一个在终止条件之后终止,另一个在结束时捕获已修剪的线程。从阅读几个网站看来,似乎void函数中的return;是不寻常的,但这种情况下有递归和多个路径,这是必需的。