I am working on a project for school that requires us to find the shortest path between two points. Basically I use a breadth first search to traverse the graph and then use a map to keep track of each cities predecessor. My idea is then that when I reach the end I will then use the edges map to find out how a city was gotten to and essentially work backwards. However when I attempt to pull values from the map all I get is null, even though when I print out the contents it shows that there is something there. If somebody could help me track down the problem I would appreciate it.
Contents of input file with each city and its neighbor:
basic
Bismark Fargo
Minneapolis Chicago
StPaul Chicago
Minneapolis StPaul
Minneapolis Fargo
Fargo GrandForks
The code (corrected version, so this code won’t exhibit the described problem any more):
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());
}
}
}
There is something wrong with your path building code:
So the node (n – 2) will never be pushed to the path, whereas the node 0 will be pushed twice.
But except for this, the program works for me. So perheaps you really have an unreachable target, as Hbcdev suggests. You should check whether or not you actually reached the end node. Note that your graph datra structure models a directed graph, so if you want to interpret your input as undirected edges, you’ll have to insert two directed edges for each line of input.
Also note that you don’t mark the initial node as seen, whereas all other nodes will get marked as seen when you add them to the queue. You should mark the first as well.
Edit:
After you pasted your (almost) complete code, I fixed it in the following ways:
java.util.*andjava.io.*. Wildcard imports are quick and dirty.}at the very end to close the class definition.basicto your input data. You really shouldSystem.exit(1)in case of that keyword missing, instead of continuing with inconsistent state.With those modifications, I tested all possible combinations of two cities, always in both orders, and including paths form a city to itself. No evidence of
nullvalues anywhere, neither in output nor as a cause of printed exceptions.