我试图实现Dijkstra算法来计算java中的k最短路径到目前为止,这里使用的代码是:
import java.util.List;
public interface AbstractKShortestPathFinder<V> {
List<Path<V>> findShortestPaths(V source, V target, Graph<V> graph, int `k);`
default void checkK(int k) {
if (k < 1) {
throw new IllegalArgumentException(
String.format("The value of k is too small: %d, should `be at least 1.", k));`
}
}
}
-
import java.util.*;
import static java.util.Objects.requireNonNull;
public class DefaultKShortestPathFinder<V> implements AbstractKShortestPathFinder<V> {
@Override
public List<Path<V>> findShortestPaths(V source, V target, Graph<V> graph, int k) {
requireNonNull(source, "The source node is null.");
requireNonNull(target, "The target node is null.");
requireNonNull(graph, "The graph is null.");
checkK(k);
List<Path<V>> paths = new ArrayList<>(k);
Map<V, Integer> countMap = new HashMap<>();
Queue<Path<V>> HEAP = new PriorityQueue<>(
Comparator.comparingDouble(Path::pathCost));
HEAP.add(new Path<>(source));
while (!HEAP.isEmpty() && countMap.getOrDefault(target, 0) < k) {
Path<V> currentPath = HEAP.remove();
V endNode = currentPath.getEndNode();
countMap.put(endNode, countMap.getOrDefault(endNode, 0) + 1);
if (endNode.equals(target)) {
paths.add(currentPath);
}
if (countMap.get(endNode) <= k) {
for (Edge<V> edge : graph.get(endNode)) {
Path<V> path = currentPath.append(edge);
HEAP.add(path);
}
}
}
return paths;
}
}
-
public class Edge<V> {
public final V from;
public final V to;
public final double weight;
public Edge(V from, V to, double weight) {
this.from = from;
this.to = to;
this.weight = weight;
if (Double.isNaN(weight)) {
throw new IllegalArgumentException("The weight is NaN.");
}
if (weight < 0.0) {
throw new IllegalArgumentException("The weight is negative.");
}
}
}
-
import java.util.*;
import static java.lang.String.*;
public class Graph<V> {
//could be replaced by http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/Table.html
private Map<V,Map<V,Edge<V>>> vertexEdgeMap = new HashMap<>();
@SafeVarargs
public Graph(Edge<V> ... edges) {
for (Edge<V> edge : edges) {
addEdge(edge);
}
}
private void addEdge(Edge<V> edge) {
vertexEdgeMap.putIfAbsent(edge.from, new HashMap<>());
Map<V, Edge<V>> fromMap = vertexEdgeMap.get(edge.from);
if(fromMap.containsKey(edge.to)) {
throw new IllegalArgumentException(format("Edge between %s and %s was added twice", edge.from, edge.to));
}
fromMap.put(edge.to, edge);
}
public Edge<V> get(V from, V to) {
return vertexEdgeMap.get(from).get(to);
}
public Collection<Edge<V>> get(V from) {
return vertexEdgeMap.getOrDefault(from, Collections.emptyMap()).values();
}
}
-
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import static java.lang.String.format;
public class Path<V> {
private final V node;
private final double totalCost;
public Path(V source) {
Objects.requireNonNull(source, "The input source node is null.");
node = source;
totalCost = 0.0;
}
private Path(V node, double totalCost) {
this.node = node;
this.totalCost = totalCost;
}
public Path<V> append(Edge<V> edge) {
if (!node.equals(edge.from)) {
throw new IllegalArgumentException(format("The edge %s doesn't extend the path %s", edge, this.getNodeList()));
}
return new NonEmptyPath<>(this, edge);
}
public V getEndNode() {
return node;
}
public List<V> getNodeList() {
return new ArrayList<>();
}
public double pathCost() {
return totalCost;
}
private static class NonEmptyPath<V> extends Path<V> {
private final Path<V> predecessor;
public NonEmptyPath(Path<V> path, Edge<V> edge) {
super(edge.to, path.totalCost + edge.weight);
predecessor = path;
}
@Override
public List<V> getNodeList() {
LinkedList<V> result = new LinkedList<>();
Path<V> path = this;
while(path instanceof NonEmptyPath) {
result.addFirst(path.node);
path = ((NonEmptyPath<V>) path).predecessor;
}
result.addFirst(path.node);
return result;
}
@Override
public String toString() {
return getNodeList().toString();
}
}
}
-
import java.util.List;
public class Execution {
public static void main(String[] args) {
execution();
}
private static void execution() {
Graph<Character> graph = new Graph<>(
// new Edge<>('a', 'b', 5.0),
new Edge<>('a', 'c', 3.0),
new Edge<>('b', 'c', 2.0),
new Edge<>('b', 'd', 1.0),
new Edge<>('c', 'd', 3.0)
);
List<Path<Character>> paths = new DefaultKShortestPathFinder<Character>().findShortestPaths('a', 'b', graph, 2);
for(Path<Character> path:paths) {
System.out.println('h');
System.out.println(path.toString() + " cout: " + path.pathCost());
}
}
}
一切都适用于有向图,但是我想修改它以便它可以计算无向图的k最短路径,任何人都知道如何实现它,我也知道对于相邻矩阵中的有向图[ a] [b] =真,但[b] [a] =假。
答案 0 :(得分:0)
无向图只是有向图,其中对于每个边a-> b,还存在边b-> a。只需将无向图转换为有向图并使用现有算法即可。