简体   繁体   English

如何实现Dijkstra算法以找到Java中的最短路径

[英]How to implement Dijkstra's Algorithm to find the shortest path in Java

I am absolutely confused on what to do. 我对做什么绝对感到困惑。 I'm trying to code off of the pseudo code that wikipedia has on Dijkstra's with priority queues, but I'm having a tough time making the adjustments to fit what i need to find. 我正在尝试从Wikipedia在Dijkstra的具有优先级队列的伪代码中编写代码,但是我很难进行调整以适应我需要找到的内容。 This is my (incomplete) code so far, and any help would be very much appreciated. 到目前为止,这是我的代码(不完整),非常感谢您的帮助。

public int doDijkstras (String startVertexName, String endVertexName, ArrayList< String > shortestPath) {
        PriorityQueue<QEntry> q = new PriorityQueue<QEntry>();
        int cost = 0;
        int newCost;
        QEntry pred = null;
        for (String s : this.getVertices()) {
            if (!s.equals(startVertexName)) {
                cost = Integer.MAX_VALUE;
                pred = null;
            }
            q.add(new QEntry(s, cost, pred, adjacencyMap.get(s)));
        }

        while (!q.isEmpty()) {
            QEntry curr = getMin(q);
            for (String s : curr.adj.keySet()) {
                newCost = curr.cost + this.getCost(curr.name, s);
                QEntry v = this.getVert(q, s);
                if (newCost < v.cost) {
                    v.cost = newCost;
                    v.pred = curr;
                    if (!q.contains(curr)) {
                        q.add(curr);
                    }
                }
            }
        }
    }

    private QEntry getMin(PriorityQueue<QEntry> q) {
        QEntry min = q.peek();
        for (QEntry temp : q) {
            if (min.cost > temp.cost) {
                min = temp;
            }
        }
        return min;
    }

    private QEntry getVert(PriorityQueue<QEntry> q, String s) {
        for (QEntry temp : q) {
            if (temp.name.equals(s)) {
                return temp;
            }
        }
        return null;
    }

    class QEntry {
        String name;
        int cost;
        QEntry pred;
        TreeMap<String, Integer> adj;

        public QEntry(String name, int cost, QEntry pred, TreeMap<String, Integer> adj) {
            this.name = name;
            this.cost = cost;
            this.adj = adj;
            this.pred = pred;
        }
    }

You are overlooking an important part of the algorithm: when to stop. 您正在忽略算法的重要部分:何时停止。

The pseudocode on Wikipedia is for the variation on Dijkstra's algorithm that computes the shortest path from the start node to every node connected to it. Wikipedia上的伪代码用于Dijkstra算法的变体,该算法计算从起始节点到与其连接的每个节点的最短路径。 Commentary immediately following the big pseudocode block explains how to modify the algorithm to find only the path to a specific target, and after that is a shorter block explaining how to extract paths. 大伪代码块之后的注释说明了如何修改算法以仅查找到特定目标的路径,然后是较短的块,说明如何提取路径。

In English, though, as you're processing your priority queue, you need to watch for the target element being the one selected. 但是,用英语来说,在处理优先级队列时,需要注意目标元素是否被选中。 When (if ever) it is, you know that no shorter path to it can be discovered than the one having the cost recorded in the target's queue entry, and represented (in reverse order) by that entry and its chain of predecessors. 无论何时(如果有的话),您都知道,找到它的最短路径就是将成本记录在目标队列条目中并由该条目及其前身链(以相反顺序)表示的路径。 You fill the path list by walking the chain of predecessors, and you return the value that was recorded in the target queue entry. 通过遍历前辈链来填充路径列表,然后返回目标队列条目中记录的值。

Note, however, that in your code, in the event that the start and target vertexes are not connected in the graph (including if the target is not in the graph at all), you will eventually drain the queue and fall out the bottom of the while loop without ever reaching the target. 但是请注意,在您的代码中,如果起始顶点和目标顶点未在图中连接(包括目标根本不在图中),最终将耗尽队列并跌出底部。而while循环却从未达到目标。 You have to decide what to do with the path list and what to return in that case. 您必须决定如何处理路径列表以及在这种情况下要返回什么。

Note, too, that your code appears to have several errors, among them: 还要注意,您的代码似乎有几个错误,其中包括:

  • In the event that the start vertex name is not the first one in the iteration order of this.getVertices() , its queue entry will not be initialized with cost 0, and will not likely be the first element chosen from the queue. 如果起始顶点名称不是this.getVertices()的迭代顺序中的第一个,则其队列条目将不会使用成本0进行初始化,并且不可能是从队列中选择的第一个元素。
  • If the specified start vertex is not in the graph at all then your code will run, and may emit a path, but its output in that case is bogus. 如果指定的起始顶点根本不在图形中,则您的代码将运行,并可能发出路径,但在这种情况下其输出是虚假的。
  • Your queue elements (type QEntry ) do not have a natural order; 您的队列元素(类型QEntry )没有自然顺序。 to create a PriorityQueue whose elements have such a type, you must provide a Comparator that defines their relative priorities. 要创建其元素具有此类的PriorityQueue ,必须提供一个Comparator来定义其相对优先级。
  • You are using your priority queue as a plain list. 您将优先级队列用作普通列表。 That in itself will not make your code produce wrong results, but it does increase its asymptotic complexity. 这本身不会使您的代码产生错误的结果,但是增加其渐近复杂性。
  • Be aware, however, that if you use the standard PriorityQueue as a priority queue, then you must never modify an enqueued object in a way that could change its order relative to any other enqueued object; 但是请注意,如果将标准PriorityQueue 用作优先级队列,则绝不能以可能改变其相对于任何其他排队对象顺序的方式修改排队对象。 instead, remove it from the queue first, modify it, then enqueue it again. 而是先将其从队列中删除,然后对其进行修改,然后再次使其入队。

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

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