【问题标题】:DFS Recursion, Revisiting nodes, even after being marked as visitedDFS 递归,重新访问节点,即使在被标记为已访问之后
【发布时间】:2015-07-29 00:22:26
【问题描述】:

所以,我一直在尝试使用递归来运行这个简单的 DFS 代码,并且我已将已访问的节点标记为已访问,但它再次循环访问已访问的节点,所以我注意到布尔数组 isVisited 已创建再次在每个递归步骤中,我无法将数组放在此方法之外的类中,并在方法中使用它。任何帮助,将不胜感激! :)

private boolean hasRoutesDFS(int start, int end) {
    if (start < 0 || start > graph.size() || end < 0 || end > graph.size())
        return false;
    boolean[] isVisited = new boolean[graph.size() + 1];

    if (start == end)
        return true;
    else{
         isVisited[start]=true;
        System.out.print(start + "->");
        for (int v : graph.getEdge(start)) {
            if (!isVisited[v] ) {
                isVisited[v] = true;
                hasRoutesDFS(v, end);
            }
        }

    }

    return false;
}

编辑: 好吧,多亏了答案中提供的技巧,我能够修复代码,现在它似乎也在处理更新的测试用例,但在某种程度上它似乎仍然是错误的,假设我给代码一个图表以下边缘:
(端点 1) (端点 2)
1 2
1 3
2 3
2 4
3 5
4 5
4 6
5 6

如果我从节点 1 到 5 搜索 DFS,我得到的答案是 1->2->3->5,这是一条有效路径,但可能还有更深的 1->2-> 4->6->5 路径也是如此,这不是 DFS 应该做的吗?走完整个深度?

新代码:

private boolean hasRoutesDFS(int start, int end) {
    return hasRoutesDFS(start, end, new boolean[graph.size() + 1]);
}

private boolean hasRoutesDFS(int start, int end, boolean[] isVisited) {
    if (start < 0 || start > graph.size() || end < 0 || end > graph.size()) {
        return false;
    }

    if (start == end) {
        System.out.print(start);
        return true;
    } else {
        isVisited[start] = true;
        System.out.print(start + "->");
        for (int v : graph.getEdge(start)) {
            if (!isVisited[v]) {
                if(hasRoutesDFS(v,end,isVisited))
                    return true;
                hasRoutesDFS(v, end, isVisited);
            }
        }

    }

    return true;
}

【问题讨论】:

    标签: java recursion depth-first-search


    【解决方案1】:

    使递归函数使用静态数据的标准技巧是将静态数据作为参数传递并从基本签名创建它。

    private boolean hasRoutesDFS(int start, int end) {
        return hasRoutesDFS(start, end, new boolean[graph.size() + 1]);
    }
    
    private boolean hasRoutesDFS(int start, int end, boolean[] isVisited) {
        if (start < 0 || start > graph.size() || end < 0 || end > graph.size()) {
            return false;
        }
    
        if (start == end) {
            return true;
        } else {
            isVisited[start] = true;
            System.out.print(start + "->");
            for (int v : graph.getEdge(start)) {
                if (!isVisited[v]) {
                    isVisited[v] = true;
                    hasRoutesDFS(v, end, isVisited);
                }
            }
    
        }
    
        return false;
    }
    

    不以任何方式暗示您的其余代码是正确的(在我看来它实际上是错误的)。只是向您展示如何避免您在每次调用时创建一个新数组时看到的问题。

    【讨论】:

    • 如果有更合法的方法,这只是一个技巧。
    • 不要忘记实际递归调用中的isVisited 变量 ;-)(最深嵌套级别的最后一行)
    • @ScottHunter - 我想说一种更合理的方法是将数组封装为对象的实例,但 OP 可能尚未涵盖 OOP。
    • @jornane - 谢谢!错过了。 :)
    • @OldCurmudgeon - 我在类似的行上编写了 BFS 代码,它运行良好,这里的逻辑对我来说似乎很好,你能告诉我为什么它看起来不对吗?
    猜你喜欢
    • 1970-01-01
    • 2011-12-10
    • 2015-09-13
    • 2018-01-19
    • 2021-03-24
    • 1970-01-01
    • 2021-04-24
    • 2010-10-24
    • 1970-01-01
    相关资源
    最近更新 更多