我知道标题有点乱,但我不知道如何更好地解释它。
我正在尝试做什么:
使用文本文件中的图形,查找并打印从顶点A到顶点B的最短路径(最小顶点数量)。
注意:使用广度优先搜索,而不是Dijkstra。
我得到了什么:
在图表上应用BFS的工作算法,但没有好方法实际打印出最短路径。
我很难区分最短路径中的顶点与简单地通过算法运行的顶点,但不是最短路径中的顶点。
例如:找到0到4之间的最短路径。 0连接到1,2和3. 1连接到4。 我的路径原来是[0,1,2,3,4]而不是[0,1,4]。
我一直无法找到任何提出相同问题的线程,或者包含此问题的BFS的任何演练,所以我不确定我是否正在将其作为方式比它更难?
编辑代码可能会让您感兴趣(如果我避开圈子,根本不确定?)
编辑2:更改了我将路径存储到堆栈的方式。
public String findPath(int v, int w) {
Queue<Integer> q = new LinkedList<Integer>();
boolean[] visited = new boolean[g.numVertices()];
q.add(v);
Stack<Integer> path = new Stack<Integer>();
while(q.peek() != null) {
runBFS(q.poll(),w,visited,q,path);
}
return path.toString();
}
private void runBFS(int v, int w, boolean[] visited, Queue<Integer> q, Stack<Integer> path) {
if(visited[v]) {
}
else if(v == w) {
path.add(v);
q.clear();
}
else {
path.add(v);
visited[v] = true;
VertexIterator vi = g.adjacentVertices(v);
while(vi.hasNext()) {
q.add(vi.next());
}
}
}
对变量和方法的一些解释:
v =原点的顶点
w =目标顶点
g = graph
vi =迭代v
的邻居的普通迭代器感谢阅读!
答案 0 :(得分:10)
您必须为每个顶点设置特定的路径字段。通过这种方式,您可以跟踪您选择的路径,从而找到短路径。我将使用一个String数组,就像您使用布尔数组存储访问顶点一样。
public String findPath(int v, int w) {
Queue<Integer> q = new LinkedList<Integer>();
boolean[] visited = new boolean[g.numVertices()];
String[] pathTo = new String[g.numVertices()];
q.add(v);
pathTo[v] = v+" ";
while(q.peek() != null) {
if(runBFS(q.poll(),w,visited,q,pathTo))
break;
}
return pathTo[w];
}
private boolean runBFS(int v, int w, boolean[] visited, Queue<Integer> q, String[] pathTo) {
if(visited[v]) {
}
else if(v == w)
return true;
}
else {
visited[v] = true;
VertexIterator vi = g.adjacentVertices(v);
while(vi.hasNext()) {
int nextVertex = vi.next();
pathTo[nextVertex] = pathTo[v] + nextVertex + " ";
q.add(nextVertex);
}
}
return false;
}
答案 1 :(得分:6)
我们助手建议并且不使用O(n ^ 2)存储空间的另一个紧凑(空间)解决方案是让每个节点仅存储它来自哪个节点。这可以通过将访问列表更改为整数数组(int[] visited
)来完成。
第1步:初始化访问列表,以便每个元素都是'-1'
或“未访问”
第2步:将第一个节点标记为自己访问visited[v] = v;
做一个BFS(就像你一样,做了以下修改:)
从v - >移动时v_next:
if(visited[v_next] == -1)
{
visited[v_next] = v;
q.put(v_next);
}
// else skip it, it's already been visited
这样,如果w可以访问,访问[w]将存储它来自哪个节点,从该节点,您可以一直回溯到v,最后以相反的顺序打印它们。 (这可以使用堆栈或递归打印方法完成。)
希望这是有道理的。 :)
答案 2 :(得分:3)
当您将一个顶点存储在BFS队列中时,还需要存储到达它的路径的副本,以便在该顶点出列时它可用。就像现在一样,您的代码不会在排队顶点上保留任何类型的路径信息 - 它只保留它访问的节点列表。
例如,您可以使用一个单独的队列,该队列将并行处理,您将在其中存储当前路径,然后在将下一个顶点出列到搜索后将其恢复。答案 3 :(得分:1)
您需要将当前节点推送到堆栈,并且只有在到达目的地后才打印整个堆栈。