难以实现BFS用于遍历图

时间:2015-07-07 13:39:59

标签: java algorithm search graph-theory adjacency-matrix

我有一个邻接矩阵adj,定义如下:

0 0 0 1 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 1 0 0 0 
1 0 0 0 1 0 1 0 0 
0 0 0 1 0 1 0 0 0 
0 0 1 0 1 0 0 0 1 
0 0 0 1 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 1 0 0 0 

我正在设计一个BFS算法,以便在给定起始位置和结束位置的情况下遍历图形。

我最好的尝试确实产生了一系列动作,但不是最短的动作。

boolean[] pass = new boolean[9]; //if a move has been done, don't redo it
int s = 0; //starting position
int e = 2; //ending position
int[][] matrix; //the adjacency matrix previous defined

public List<Integer> BFS(int[][] matrix, int s) {
    List<Integer> paths = new LinkedList();
    List<Integer> shortest = new LinkedList();
    pass[s] = true; //starting position has been indexed
    paths.add(0,s); //insert part of path to front of list
    while (paths.isEmpty() == false) {
        int element = paths.get(0); //peek at first element
        shortest.add(element); //add it to shortest path
        int node = paths.remove(0); //remove from path
        if (element == e) { //if we've reached the end
            return shortest; //hopefully found shortest path
        } else {
            for (int i = 0; i < 9; i++) {
                //if adjacent element hasn't been indexed
                if (pass[i] == false && matrix[node][i] == 1) {
                    pass[i] = true;
                    paths.add(0,i);
                }
            }
        }
    }
    return null;
}

打印返回的列表产生:

[0, 3, 6, 4, 5, 8, 2]

当实际结果应为:

[0, 3, 4, 5, 2]

在我看来,它所走的道路就是:

[0, 3, 6, backtrack to 3, 4, 5, 8, backtrack to 5, 2]

我的算法出了什么问题?如何找到给定起点和终点的最短路径?

Here是一个可以说明的理念。

2 个答案:

答案 0 :(得分:2)

您的实施中的shortest数组不是您认为的那样。它只是找到的所有顶点的列表,而不是最短的路径,因为(正如您所知)BFS有时必须遵循不通向目标顶点的路径。

你需要做的是为每个顶点v存储它的“父” - 你来自v的顶点:

       if (pass[i] == false && matrix[node][i] == 1) {
            pass[i] = true;
            parent[i] = node;
            paths.add(0,i);
       }

然后在主BFS循环之后,使用parent中存储的链接从目标顶点返回源:

// pseudocode
cur = e;
while cur != s
    answer.add_at_end(cur)
    cur = parent[cur];

答案 1 :(得分:1)

您无法正确提取最短路径。您正在将您处理的每个节点添加到最短路径。

如果要使用BFS查找最短路径,则必须通过存储&#34;后沿&#34;来跟踪到每个中间节点的最短路径。只有到最后你才能把它们放在一起找到最短的路径。

对于您添加到队列中的每个节点,将您到达此节点的节点存储为&#34;后边缘&#34;:

if (pass[i] == false && matrix[node][i] == 1) {
    pass[i] = true;
    paths.add(0,i);

    // Add this:
    back[i] = node;
}

然后,一旦你的遍历完成,你可以使用这些参考来找到完整的路径,去那些&#34;后边缘&#34;从末端节点向后移动。它将引导您(向后)到最短路径上的起始节点:

int node = e;
while (node != s) {
    shortest.add(0, node);
    node = back[node];
}
shortest.add(0, s);

<强>更新

感谢您的评论,我刚刚意识到您的代码还存在其他问题。您正在将新节点添加到列表的前面,并从前面处理它们。所以你实际上有一个堆栈,而不是一个队列。这使得您的算法有效地成为深度优先搜索(DFS)而不是广度优先搜索(BFS)。 DFS将为您提供从se的正确路径,但不一定是最短路径。

为了将列表paths(最好将其命名为queue,btw。)作为队列而不是堆栈处理,您必须从相反的两端读取和写入,例如:添加到后面(而不是前面)更改列表添加行

paths.add(0, i);

paths.add(i);