简体   繁体   English

无法使用Dijkstra算法找到最短路径?

[英]Not able to find shortest path using Dijkstra algorithm?

I am trying to find shrotest path between node a and z using Dijkstra algorithm but everytime it is giving me wrong response. 我试图使用Dijkstra算法在节点az之间找到最短的路径,但是每次它给我错误的响应。

Below is the code I have - 下面是我的代码-

public class DijkstraAlgorithm {

    // Am I mapping this correctly by looking at the below graph?
    // looks to me I got this wrong?
    private static final Graph.Edge[] GRAPH = { 
        new Graph.Edge("a", "g", 8), 
        new Graph.Edge("a", "b", 1), 
        new Graph.Edge("a", "e", 1), 
        new Graph.Edge("b", "c", 1), 
        new Graph.Edge("b", "e", 1),
        new Graph.Edge("b", "f", 2),
        new Graph.Edge("c", "g", 1),
        new Graph.Edge("c", "d", 1),
        new Graph.Edge("d", "f", 1),
        new Graph.Edge("d", "z", 1),
        new Graph.Edge("e", "f", 4),
        new Graph.Edge("f", "z", 4),
        new Graph.Edge("g", "z", 2),
    };

    private static final String START = "a";
    private static final String END = "z";

    public static void main(String[] args) {
        Graph g = new Graph(GRAPH);
        g.dijkstra(START);
        //  print the shortest path using Dijkstra algorithm
        g.printPath(END);
        //g.printAllPaths();
    }
}

class Graph {
    private final Map<String, Vertex> graph; // mapping of vertex names to Vertex objects, built from a set of Edges

    /** One edge of the graph (only used by Graph constructor) */
    public static class Edge {
        public final String v1, v2;
        public final int dist;

        public Edge(String v1, String v2, int dist) {
            this.v1 = v1;
            this.v2 = v2;
            this.dist = dist;
        }
    }

    /** One vertex of the graph, complete with mappings to neighbouring vertices */
    public static class Vertex implements Comparable<Vertex> {
        public final String name;
        public int dist = Integer.MAX_VALUE; // MAX_VALUE assumed to be infinity
        public Vertex previous = null;
        public final Map<Vertex, Integer> neighbours = new HashMap<Vertex, Integer>();

        public Vertex(String name) {
            this.name = name;
        }

        private void printPath() {
            if (this == this.previous) {
                System.out.printf("%s", this.name);
            } else if (this.previous == null) {
                System.out.printf("%s(unreached)", this.name);
            } else {
                this.previous.printPath();
                System.out.printf(" -> %s(%d)", this.name, this.dist);
            }
        }

        public int compareTo(Vertex other) {
            return Integer.compare(dist, other.dist);
        }
    }

    /** Builds a graph from a set of edges */
    public Graph(Edge[] edges) {
        graph = new HashMap<String, Vertex>(edges.length);

        //one pass to find all vertices
        for (Edge e : edges) {
            if (!graph.containsKey(e.v1))
                graph.put(e.v1, new Vertex(e.v1));
            if (!graph.containsKey(e.v2))
                graph.put(e.v2, new Vertex(e.v2));
        }

        //another pass to set neighbouring vertices
        for (Edge e : edges) {
            graph.get(e.v1).neighbours.put(graph.get(e.v2), e.dist);
            graph.get(e.v2).neighbours.put(graph.get(e.v1), e.dist); // also do this for an undirected graph
        }
    }

    /** Runs dijkstra using a specified source vertex */
    public void dijkstra(String startName) {
        if (!graph.containsKey(startName)) {
            System.err.printf("Graph doesn't contain start vertex \"%s\"\n", startName);
            return;
        }
        final Vertex source = graph.get(startName);
        NavigableSet<Vertex> q = new TreeSet<Vertex>();

        // set-up vertices
        for (Vertex v : graph.values()) {
            v.previous = v == source ? source : null;
            v.dist = v == source ? 0 : Integer.MAX_VALUE;
            q.add(v);
        }

        dijkstra(q);
    }

    /** Implementation of dijkstra's algorithm using a binary heap. */
    private void dijkstra(final NavigableSet<Vertex> q) {
        Vertex u, v;
        while (!q.isEmpty()) {

            u = q.pollFirst(); // vertex with shortest distance (first iteration will return source)
            if (u.dist == Integer.MAX_VALUE)
                break; // we can ignore u (and any other remaining vertices) since they are unreachable

            //look at distances to each neighbour
            for (Map.Entry<Vertex, Integer> a : u.neighbours.entrySet()) {
                v = a.getKey(); //the neighbour in this iteration

                final int alternateDist = u.dist + a.getValue();
                if (alternateDist < v.dist) { // shorter path to neighbour found
                    q.remove(v);
                    v.dist = alternateDist;
                    v.previous = u;
                    q.add(v);
                }
            }
        }
    }

    /** Prints a path from the source to the specified vertex */
    public void printPath(String endName) {
        if (!graph.containsKey(endName)) {
            System.err.printf("Graph doesn't contain end vertex \"%s\"\n", endName);
            return;
        }

        graph.get(endName).printPath();
        System.out.println();
    }

    /** Prints the path from the source to every vertex (output order is not guaranteed) */
    public void printAllPaths() {
        for (Vertex v : graph.values()) {
            v.printPath();
            System.out.println();
        }
    }
}

As per the calculation shortest path from node A to node Z is ABCDZ but I am getting A -> E(1) -> F(5) -> D(6) -> Z(7) from my above code which is wrong. 根据计算从节点A到节点Z最短路径是ABCDZ但是我从上面的代码中得到A -> E(1) -> F(5) -> D(6) -> Z(7) ,这是错误的。

I guess, my mapping of graph data values in the above code is wrong by looking at the graph? 我想,通过查看图表,我在上面代码中对图表数据值的映射是错误的吗? Is there any better way I should try to represent my graph? 有什么更好的方法可以尝试代表我的图表吗?

Is there anything wrong in my above code? 我上面的代码有什么问题吗?

The problem is your queue structure. 问题是您的队列结构。 It is based on a TreeSet which uses your compare function to order things. 它基于TreeSet,该TreeSet使用您的compare函数对事物进行排序。 Unfortunately, a TreeSet can only have a single value for each key, and so if two elements compare equal (eg all the vertices with MAXINT distance will compare equal) they effectively get removed. 不幸的是,每个键的TreeSet只能有一个值,因此,如果两个元素比较相等(例如,具有MAXINT距离的所有顶点将比较相等),则它们实际上被删除了。

You can see this by printing out the length of the queue, you insert 8 elements, but it only gets to be of size 2. 您可以通过打印出队列的长度来看到这一点,插入8个元素,但是大小只有2。

One simple workaround is: 一种简单的解决方法是:

    public int compareTo(Vertex other) {
        if (dist==other.dist)
            return name.compareTo(other.name);
        return Integer.compare(dist, other.dist);
    }

This stops different vertices from being compared as equal. 这将阻止不同的顶点被相等地比较。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM