我正在为学校开展一个项目,要求我们找到两点之间的最短路径。基本上我使用广度优先搜索来遍历图形,然后使用地图来跟踪每个城市的前身。我的想法是,当我到达终点时,我将使用边缘地图来了解城市是如何获得的并且基本上是向后工作。然而,当我尝试从地图中提取值时,我得到的全部都是空的,即使我打印出内容时它显示那里有东西。如果有人能帮我追踪问题,我会很感激。
每个城市及其邻居的输入文件的内容:
basic
Bismark Fargo
Minneapolis Chicago
StPaul Chicago
Minneapolis StPaul
Minneapolis Fargo
Fargo GrandForks
代码(更正版本,因此此代码不再显示所描述的问题):
import java.util.*;
import java.io.*;
public class BFSBasics {
public static void main(String[] args) throws FileNotFoundException {
Map<String, List<String>> graph = new HashMap<>();
openFile(graph, args[0]);
String start = args[1];
String end = args[2];
BFS(graph, start, end);
}
public static void openFile(Map<String,List<String>> graph,
String file)
throws FileNotFoundException{
Map<String,List<String>> aGraph = new HashMap<>();
try (Scanner scan = new Scanner(new File(file))){
if(!scan.next().equals("basic")){
System.err.println("File cannot be read.");
System.exit(1);
}else{
while(scan.hasNext()){
String city1 = scan.next();
String city2 = scan.next();
addEdge(graph, city1, city2);
addEdge(graph, city2, city1);
}
}
}
}
private static void addEdge(Map<String, List<String>> graph, String city1,
String city2){
List<String> adjacent = graph.get(city1);
if(adjacent == null){
adjacent = new ArrayList<>();
graph.put(city1, adjacent);
}
adjacent.add(city2);
}
public static void BFS(Map<String, List<String>> graph, String start,
String end) {
boolean done = false;
//cities that still need to be worked on
Queue<String> work = new ArrayDeque<>();
//cities that have already been seen
Set<String> seen = new HashSet<>();
//cities predecessor i.e. how it was gotten to
Map<String, String> edges = new HashMap<>();
LinkedList<String> path = new LinkedList<>();
String city = start;
work.add(start);
while (!done && !work.isEmpty()) {
city = work.remove();
for (String s : graph.get(city)) {
if (!seen.contains(s)) {
edges.put(s, city);
work.add(s);
seen.add(s);
if (s.equals(end)) {
done = true;
}
}
}
}
//Work backwards through the edges map and push onto the path stack
path.push(end);
String temp = edges.get(end);
while(!temp.equals(start)){
path.push(temp);
temp = edges.get(path.peek()};
}
path.push(start);
//print out the path
while(!path.isEmpty()){
System.out.println(path.pop());
}
}
}
答案 0 :(得分:1)
您的构建代码的路径有问题:
path.push(end); // push node (n - 1)
String temp = edges.get(end); // temp = node (n - 2)
while(!temp.equals(start)){
path.push(edges.get(temp)); // push node (n - 3) down to and including node 0
temp = path.peek(); // temp = node (n - 3) down to and including node 0
}
path.push(start); // push node 0
因此节点( n - 2)永远不会被推送到路径,而节点0将被推送两次。
但除此之外,该计划适合我。因此,如Hbcdev所示,你真的有一个无法到达的目标。您应该检查是否实际到达了结束节点。请注意,图形数据结构模拟定向图形,因此如果要将输入解释为无向边缘,则必须为每条线插入两条有向边。输入
另请注意,您不会将初始节点标记为已显示,而将所有其他节点添加到队列时将标记为已标记。你也应该标记第一个。
修改强>
在粘贴(几乎)完整代码后,我通过以下方式修复它:
java.util.*
和java.io.*
添加了两个通配符导入。通配符导入快速而且脏。}
以关闭类定义。basic
。如果缺少该关键字,您确实应System.exit(1)
,而不是继续处于不一致状态。通过这些修改,我测试了两个城市的所有可能组合,总是在两个顺序中,并且包括从一个城市到自身的路径。任何地方都没有null
值的证据,既不是输出也不是打印异常的原因。
答案 1 :(得分:-1)
我在这里看到了几个可能的问题。直接原因可能是:您的逻辑隐含地假设只有一种方法可以到达任何给定节点。虽然这可能是真的,但我对此表示怀疑。如果有两种方法可以到达同一个节点,则用地图中的第二个覆盖第一个节点。
例如,假设输入为:
A->B
C->B
B->E
D->E
你想从A到E.这可以通过A,B,E来完成。但是当你构建你的地图时,你将为B,A创建一个边缘条目。然后你会写B, C,覆盖B,A。然后你写E,B。好。然后你写E,D,重写E,B。所以当你完成时,边缘图中的所有内容都是(B,C)和(E,D)。然后你试着从E向后走。你找到E,D。但这是错的:你想要E,B,但是被覆盖了。当你试图找到D的条目时,没有,所以不可能回到A。
第二个问题是你说目标是从头到尾找到SHORTEST路径。但是你没有做任何事情来找到最短的路径:一旦找到任何路径就停止寻找。原则上,您确实需要找到所有可能的路径,然后从该列表中选择最短路径。 (或者希望,随着时间的推移消除更长的路径,无论如何。)