递归函数中的for循环在递归结束后继续

Posted

技术标签:

【中文标题】递归函数中的for循环在递归结束后继续【英文标题】:For loop in recursive function continues after end of recursion 【发布时间】:2017-04-05 16:00:23 【问题描述】:

我在 C++ 中的图上实现深度优先搜索。给定一个起始顶点,算法应该执行 DFS,直到找到一个目标节点(即一个将 goal 设置为 true 的节点),并返回所采用的路径。我正在尝试以递归方式执行此操作,这是我的代码:

vector<char>* dfs(graph g, node* s)

    static vector<char> path;
    s->set_visited();
    path.push_back(s->get_tag()); //Adds node to path

    if(s->is_goal())
        g.set_all_visited();
    

    else
        for(int i=0; i<(s->get_no_edges()); i++)
            if(!(s->get_edge(i)->get_dest()->is_visited())) //If it is unvisited, apply recursion
                dfs(g, s->get_edge(i)->get_dest());
        
    

    return &path;

我知道生成的路径只会按照 DFS 访问的顺序列出节点,而不是从起点到目标节点的实际路径。

问题在于,即使找到目标节点,该函数仍会继续打印节点。为了避免这种情况,我将图表g 中的所有节点设置为使用set_all_visited() 访问,并在继续之前检查else 部分是否访问了节点,但这似乎不起作用。当我执行空运行时,即使在找到目标节点后,该函数仍会继续访问 for 循环中节点的所有边缘,我不知道如何阻止这种情况发生。

【问题讨论】:

可能与按值传递 g 有关。尝试通过引用传递它。您将所有节点标记为已访问的g 与其他递归调用可用的g 不同。 ericlippert.com/2014/03/05/how-to-debug-small-programs 特别是在这种情况下,您似乎确定它处于 for 循环中——因此 i&lt;(s-&gt;get_no_edges()) 是正确的。因此,在调试器中查看is-&gt;get_no_edges()(或使用cout,穷人的调试器),并亲自了解为什么条件仍然成立。 @IVlad 我试过了,现在似乎可以工作了!这么愚蠢的错误。谢谢! 我不知道您对graph 的实现,但您确定要通过值而不是通过引用dfs 来传递它吗?也许您每次调用它时都会创建一个图的副本?但总的来说,对于 DFS 实现,您的代码中存在许多问题。 @AlexanderStante 具体来说? 【参考方案1】:

您通过值而不是通过引用传递g。这意味着,每当您找到目标节点并从递归调用中返回时,g 的实例仍会将其节点设置为未访问。这就是重复发生的原因。

【讨论】:

【参考方案2】:

我知道您的主要问题已得到解答,但我仍会给出一些建议:

1) 不要使用静态向量,不能重用函数。您可以改为在您期望路径的地方创建一个向量并将指针传递给该向量。

2) 为确保路径中没有所有访问过的节点,您可以从 dfs 函数返回一个布尔值来表示是否有到目的地的路径。您也可以避免通过这种方式传递图形对象。

通过这些更改,您的代码将变为:

bool dfs(node* s, vector<char>* path)

    s->set_visited();

    if(s->is_goal())
        path.push_back(s->get_tag());
        return true;
    

    else
        for(int i=0; i<(s->get_no_edges()); i++)
            if(!(s->get_edge(i)->get_dest()->is_visited())) //If it is unvisited, apply recursion
                if(dfs(s->get_edge(i)->get_dest(), path)) 
                    path.push_back(s->get_tag());
                    return true;
                
        
    

    return false;

这将返回反向路径,即从目标到源的路径,有std::reverse。

如果你做一个 BFS,你会得到最短路径而不是一些随机路径,假设边的权重相等。

【讨论】:

以上是关于递归函数中的for循环在递归结束后继续的主要内容,如果未能解决你的问题,请参考以下文章

使用递归方法和for循环方法求阶乘

函数的递归

数据结构-- 递归 排序

python 函数的进阶

数据结构——递归

递归函数