为什么这个DFS代码在某些情况下不起作用?

时间:2015-06-20 08:01:59

标签: java data-structures dfs

enter image description here

根据上面的图片,DFS应该是:0 1 3 5 4 2但它正在返回0 1 3 5 2(这只发生在一个案例中。我在这里做错了什么?)

代码:

import java.util.Stack;

public class DFSDetectCycleSelf {

static int arr[][] = {
        { 0, 1, 1, 0, 0, 0 },
        { 0, 0, 0, 1, 0, 0 },
        { 0, 0, 0, 0, 0, 0 },
        { 0, 0, 0, 0, 0, 1 },
        { 0, 0, 0, 0, 0, 0 },
        { 0, 0, 0, 0, 1, 0 }
        //working fine for static int arr[][]={{0,1,1,0,0,0},
        // {0,0,0,1,1,0},
        //{0,0,0,0,0,1},
        //{0,0,0,0,0,0},
        //{0,0,0,0, 0,0},
        //{0,0,0,0,0,0}};
static Stack<Integer> stack;

DFSDetectCycleSelf(){
    stack = new Stack<Integer>();
}

public static void main(String[] args){
    DFSDetectCycleSelf df = new DFSDetectCycleSelf();
    PrintDFS();

}

public static void PrintDFS(){
    int source = 0;
    int numberOfNodes = arr[source].length;
    int [] visited = new int[numberOfNodes];
    int v;
    stack.push(source);


    while (!stack.isEmpty()){
        v = stack.pop();
        if(visited[v]==0) {
            visited[v] = 1;
            System.out.println(v);
        }

        for(int i=0;i<numberOfNodes;i++){
            if(arr[v][i]==1 && visited[i]==0){
                stack.push(v);
                System.out.println(i);
                visited[i]=1;
                v = i;
            }
        }

    }
}

}

2 个答案:

答案 0 :(得分:2)

这应该有效:

public static void PrintDFS(){
    int source = 0;
    int numberOfNodes = arr[source].length;
    int [] visited = new int[numberOfNodes];
    int v;
    stack.push(source);


    while (!stack.isEmpty()){
        v = stack.pop();
        if(visited[v]==0) {
          visited[v] = 1;
          System.out.println(v);
          for(int i=0;i<numberOfNodes;i++){
            if(arr[v][i]==1)
              stack.push(i);
          }
        }
    }
}

原始代码中的主要问题是for-loop:当arr[v][i] == 1时,i表示v的邻居i。您不应该将v推入堆栈而不是v:您想要访问v的邻居,而不是再次重新访问visited[i] == 0

此外,在将i推入堆栈之前无需检查i。当从堆栈中弹出arr(稍后)时,代码将检查其访问状态。

<强>更新

(a)输入( static int arr[][] = { { 0, 1, 1, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1, 0 } }; )不反映问题开头提供的图表。需要将其更改为:

(x) -> (y)

(b)如果边缘是有序的(在某种意义上边缘(x) -> (y+1)应该在边缘 for (int i = numberOfNodes - 1; i >= 0; i--) { 之前遍历)那么确实如前面Alexis C所建议的那样,for循环需要向后退去

0
1
3
5
4
2

应用了以下修正:输出变为:

this

答案 1 :(得分:0)

您的代码存在问题

...
v = i; // shouldn't be there
...

这是访问图中所有节点的一般情况迭代算法

WHILE there exists a graph node not marked loop
    Find an unmarked node F
    Add node F to collection (stack or queue)
    WHILE the collection is not empty loop
        Remove a node N from the collection
        IF the node N is unmarked
            Mark node N
            Add all adjacent nodes of node N to the collection
            Process node N

集合取决于您需要解决的问题。如果通过查看最短路径来解决问题,那么队列(意思是BFS)就是可行的方法。如果问题将通过了解迷宫中所采用的路线来解决,那么堆栈(意思是DFS)就要走了。此外,对于您知道根节点的树(如此问题),算法的前两行是不必要的。

内循环的一个重要部分是准备相邻节点的未来处理,但重要的是不要跟随这些链接到相邻节点,v = i;通过跟随链接来改变节点。没有必要遵循链接,因为这些节点正在放置在集合中,并且将来会被处理。

内循环的作用仅限于节点N.这个问题的分区有助于简化算法,并且更容易执行更大的任务,即只访问和处理所有节点一次。