ОБНОВЛЕНИЕ: Изменено имя узлов и ребер, а также ребер списка.
Похоже, много кода для этого.Вот альтернативная реализация Java 8+.
Алгоритм Дейкстры полностью реализован в методе startAt
.
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeSet;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public final class Graph {
private static final class Edge {
final String name;
final int weight;
Edge(String name, int weight) {
this.name = name;
this.weight = weight;
}
@Override
public String toString() {
return this.name + ":" + this.weight;
}
}
private static final class Node {
final String name;
Map<Node, Edge> edges = new HashMap<>();
Node[] path;
int pathWeight;
Node(String name) {
this.name = name;
}
}
private Map<String, Node> nodes = new HashMap<>();
public void addEdge(String sourceName, String destinationName, int weight, String edgeName) {
Node source = this.nodes.computeIfAbsent(sourceName, Node::new);
Node dest = this.nodes.computeIfAbsent(destinationName, Node::new);
Edge edge = new Edge(edgeName, weight);
source.edges.put(dest, edge);
dest.edges.put(source, edge);
}
public void startAt(String startNodeName) {
this.nodes.values().forEach(n -> n.path = null);
Node source = this.nodes.computeIfAbsent(startNodeName, Node::new);
source.path = new Node[] { source };
source.pathWeight = 0;
TreeSet<Node> pending = new TreeSet<>((a, b) -> Integer.compare(a.pathWeight, b.pathWeight));
pending.add(source);
while ((source = pending.pollFirst()) != null) {
for (Entry<Node, Edge> edge : source.edges.entrySet()) {
Node dest = edge.getKey();
int weight = source.pathWeight + edge.getValue().weight;
if (dest.path == null || weight < dest.pathWeight
|| (weight == dest.pathWeight && source.path.length + 1 < dest.path.length)) {
if (dest.path != null)
pending.remove(dest);
dest.path = Arrays.copyOf(source.path, source.path.length + 1);
dest.path[source.path.length] = dest;
dest.pathWeight = weight;
pending.add(dest);
}
}
}
}
public String getPath(String endNodeName) {
Node node = this.nodes.get(endNodeName);
if (node == null || node.path == null)
return "Unreachable";
String path = Arrays.stream(node.path).map(n -> n.name).collect(Collectors.joining(" - "));
String pathEdges = IntStream.range(1, node.path.length)
.mapToObj(i -> node.path[i - 1].edges.get(node.path[i]).toString())
.collect(Collectors.joining(" + "));
return path + " (distance: " + node.pathWeight + " = " + pathEdges + ")";
}
}
Тест 1 (исходные ребра))
Graph graph = new Graph();
graph.addEdge("0", "1", 4, "A");
graph.addEdge("0", "2", 3, "B");
graph.addEdge("1", "2", 1, "C");
graph.addEdge("1", "3", 2, "D");
graph.addEdge("2", "3", 4, "E");
graph.addEdge("3", "4", 2, "F");
graph.addEdge("4", "5", 6, "G");
graph.startAt("0");
System.out.println(graph.getPath("5"));
Выход 1
0 - 1 - 3 - 4 - 5 (distance: 14 = A:4 + D:2 + F:2 + G:6)
Тест 2 (обновленные ребра)
Graph graph = new Graph();
graph.addEdge("0", "1", 4, "A");
graph.addEdge("0", "2", 3, "B");
graph.addEdge("1", "3", 2, "C");
graph.addEdge("1", "2", 5, "D");
graph.addEdge("2", "3", 7, "E");
graph.addEdge("3", "4", 2, "F");
graph.addEdge("4", "0", 4, "G");
graph.addEdge("4", "1", 4, "H");
graph.addEdge("4", "5", 6, "I");
graph.startAt("0");
System.out.println(graph.getPath("5"));
Выход 2
0 - 4 - 5 (distance: 10 = G:4 + I:6)
См. IDEONE для демонстрации обоих тестов.