Dijkstra 最短路径算法与 JGraphT 实现的结果不匹配

问题描述 投票:0回答:1

我正在尝试为 Dijkstra 最短路径算法编写自己的代码,基于我在以下网站上找到的伪代码: https://www.freecodecamp.org/news/dijkstras-algorithm-explained-with-a-pseudocode-example/

但是,当将我的代码实现的结果与 JGraphT 库中的 DijksraShortestPath 实现进行比较时,结果是不同的。我希望我的代码与 JGraphT 实现的结果相匹配。

这是我的代码:

package pckg;

import java.util.ArrayList;
import java.util.Set;

import org.jgrapht.alg.interfaces.ShortestPathAlgorithm.SingleSourcePaths;
import org.jgrapht.alg.shortestpath.DijkstraShortestPath;
import org.jgrapht.graph.DefaultUndirectedWeightedGraph;
import org.jgrapht.graph.DefaultWeightedEdge;

public class Dijkstra {
    
    static DefaultUndirectedWeightedGraph<String, DefaultWeightedEdge> map = Map.createMap();
    
    public static void main(String[] args) {
        DijkstraShortestPath<String, DefaultWeightedEdge> test = new DijkstraShortestPath<String, DefaultWeightedEdge>(map);
        SingleSourcePaths<String, DefaultWeightedEdge> paths = test.getPaths("0");
        
        
        ArrayList<double[]> dijkstraData = dijkstra(map, 0);
        
        double[] dist = dijkstraData.get(0);
        double[] pred = dijkstraData.get(1);
        
        for (int i = 0; i <= 35; i++) {
            String s = Integer.toString(i);
            System.out.println( 
                    "JGraphT: " + paths.getWeight(s) + 
                    "    -    My code:  " + dist[i]);
        }
        
        
    }
    
    
    public static ArrayList<double[]> dijkstra(DefaultUndirectedWeightedGraph<String, DefaultWeightedEdge> graph, int source) {
        
        final double inf = 1.0/0.0; //dividing by zero gives infinity
        
        double[] dist = new double[ graph.vertexSet().size() ];
        double[] pred = new double[ graph.vertexSet().size() ];
        
        
        ArrayList<Integer> Q = new ArrayList<Integer>(0);
        
        Set<String> vertexSet = graph.vertexSet();
        
        for (String vString : vertexSet) { //for each vertex v in Graph.Vertices:
            int v = Integer.parseInt(vString);
            
            
            dist[v] = inf; //dist[v] ← INFINITY
            pred[v] = -1; //prev[v] ← UNDEFINED
            
            Q.add(v); //add v to Q
        }
        
        dist[source] = 0; //dist[source] ← 0
        
        while (!Q.isEmpty()) { //while Q is not empty:
            
            // Find minimum element in Q based on dist values
            int min = Q.get(0);
            for (int i : Q) {
                if (dist[i] < dist[min]) {
                    min = i;
                }
            }
            

            int u = min; //u ← vertex in Q with min dist[u]
            
            Q.remove(Integer.valueOf(u)); // Remove u from Q

            
            ArrayList<Integer> neighbours = new ArrayList<Integer>(0); 
            
            for (int node : Q) { //for each neighbor v of u still in Q:
                
                //get all neighbours of of u still in Q
                Set<DefaultWeightedEdge> edges = graph.edgesOf(Integer.toString(node));
                for (DefaultWeightedEdge edge : edges) 
                    if (!neighbours.contains( Integer.parseInt( graph.getEdgeTarget(edge) ) ))
                        neighbours.add( Integer.parseInt( graph.getEdgeTarget(edge) ) );
            }
            
            
            for (int v : neighbours) { // for each neighbor v of u still in Q:
                
                DefaultWeightedEdge edge = graph.getEdge(Integer.toString(u), Integer.toString(v));
                if (edge == null) { continue; } //check if edge exists
                //System.out.println(edge.toString());
                double alt = dist[u] +  graph.getEdgeWeight( edge );  //alt ← dist[u] + Graph.Edges(u, v)
                if (alt < dist[v] ) { //if alt < dist[v]:
                    dist[v] = alt; //dist[v] ← alt
                    pred[v] = u; // prev[v] ← u
                }
            }
            
            
        }
        
        ArrayList<double[]> returnData = new ArrayList<double[]>(0);
        returnData.add(dist);
        returnData.add(pred);
        
        return returnData;
    
    }

}

结果如下:

JGraphT: 0.0    -    My code:  0.0
JGraphT: 633.0    -    My code:  Infinity
JGraphT: 551.0    -    My code:  551.0
JGraphT: 421.0    -    My code:  421.0
JGraphT: 352.0    -    My code:  352.0
JGraphT: 305.0    -    My code:  305.0
JGraphT: 250.0    -    My code:  250.0
JGraphT: 304.0    -    My code:  304.0
JGraphT: 662.0    -    My code:  662.0
JGraphT: 702.0    -    My code:  773.0
JGraphT: 506.0    -    My code:  506.0
JGraphT: 438.0    -    My code:  438.0
JGraphT: 381.0    -    My code:  381.0
JGraphT: 341.0    -    My code:  341.0
JGraphT: 698.0    -    My code:  698.0
JGraphT: 710.0    -    My code:  710.0
JGraphT: 708.0    -    My code:  708.0
JGraphT: 623.0    -    My code:  623.0
JGraphT: 532.0    -    My code:  532.0
JGraphT: 477.0    -    My code:  477.0
JGraphT: 763.0    -    My code:  763.0
JGraphT: 776.0    -    My code:  776.0
JGraphT: 782.0    -    My code:  782.0
JGraphT: 698.0    -    My code:  698.0
JGraphT: 611.0    -    My code:  611.0
JGraphT: 770.0    -    My code:  770.0
JGraphT: 663.0    -    My code:  663.0
JGraphT: 628.0    -    My code:  628.0
JGraphT: 518.0    -    My code:  518.0
JGraphT: 471.0    -    My code:  471.0
JGraphT: 444.0    -    My code:  444.0
JGraphT: 716.0    -    My code:  716.0
JGraphT: 614.0    -    My code:  614.0
JGraphT: 527.0    -    My code:  527.0
JGraphT: 700.0    -    My code:  700.0
JGraphT: 755.0    -    My code:  755.0

我不明白为什么结果不同,希望得到解释并可能解决我的问题。预先感谢您。

java shortest-path dijkstra jgrapht
1个回答
0
投票

您的实现中的问题似乎与

pred
数组的初始化以及您处理算法中前辈的方式有关。前驱数组 (
pred
) 旨在存储从源到每个节点的最短路径中的前一个节点。

这是您的

Dijkstra
方法的更正版本:

public static ArrayList<double[]> dijkstra(DefaultUndirectedWeightedGraph<String, DefaultWeightedEdge> graph, int source) {
final double inf = Double.POSITIVE_INFINITY;

double[] dist = new double[graph.vertexSet().size()];
int[] pred = new int[graph.vertexSet().size()];

ArrayList<Integer> Q = new ArrayList<Integer>(0);

Set<String> vertexSet = graph.vertexSet();

for (String vString : vertexSet) {
    int v = Integer.parseInt(vString);

    dist[v] = inf;
    pred[v] = -1;

    Q.add(v);
}

dist[source] = 0;

while (!Q.isEmpty()) {
    int min = Q.get(0);
    for (int i : Q) {
        if (dist[i] < dist[min]) {
            min = i;
        }
    }

    int u = min;
    Q.remove(Integer.valueOf(u));

    Set<DefaultWeightedEdge> edges = graph.edgesOf(Integer.toString(u));
    for (DefaultWeightedEdge edge : edges) {
        int v = Integer.parseInt(graph.getEdgeTarget(edge));
        double alt = dist[u] + graph.getEdgeWeight(edge);
        if (alt < dist[v]) {
            dist[v] = alt;
            pred[v] = u;
        }
    }
}

ArrayList<double[]> returnData = new ArrayList<double[]>(0);
returnData.add(dist);
returnData.add(Arrays.stream(pred).asDoubleStream().toArray());

return returnData;}

主要变化:

  1. pred
    数组的类型更改为
    int[]
    ,因为它存储顶点索引。
  2. 不是直接在输出中使用
    pred
    ,而是使用
    Arrays.stream(pred).asDoubleStream().toArray()
    将其转换为双精度数组。

请注意,这个更正后的版本应该更符合 Dijkstra 算法中前驱数组的预期用途。另外,在将结果与 JGraphT 进行比较时,请记住,浮点比较有时会因精度问题而导致较小的差异,因此,如有必要,最好使用较小的 epsilon 值进行此类比较。

© www.soinside.com 2019 - 2024. All rights reserved.