簡體   English   中英

使用優先級隊列實現 Dijkstra 算法

[英]implementing dijkstra's algorithm using a priority queue

所以我正在嘗試實現 Dijkstra 算法。 我理解 Dijkstra 的作品,但我很難將概念轉化為代碼。 我有我認為正確的代碼,我在 java 堆空間上遇到內存不足異常,我不確定為什么。 我也對我的實施失去了所有信心,所以任何反饋都會很棒

    protected Path dijkstrasShortestPath(T start, T end) {
        if (start == null || end == null) {
            throw new NoSuchElementException("Vertices cannot have null data");
        }
        if (vertices.get(start) == null || vertices.get(end) == null) {
            throw new NoSuchElementException("Vertices do not exist");
        }
        PriorityQueue<Path> pq = new PriorityQueue<Path>();
        LinkedList<Vertex> visited = new LinkedList<Vertex>();
        Path startPath = new Path(vertices.get(start));
        visited.add(startPath.start);
        pq.add(startPath);
        while (!pq.isEmpty()) {
            Path front = pq.poll();
            visited.add(front.end);
            if (front.end.data.equals(end)) {
                return front;
            } else {
                for (int i = 0; i < front.end.edgesLeaving.size(); i++) {
                    if (!visited.contains(front.end.edgesLeaving.get(i).target)) {
                        pq.add(new Path(front, front.end.edgesLeaving.get(i)));
                    }
                }
            }
        }

        throw new NoSuchElementException("No such path from start to end exists");
    }

這些是我使用的其他一些類和字段

/**
     * Vertex objects group a data field with an adjacency list of weighted
     * directed edges that lead away from them.
     */
    protected class Vertex {
        public T data; // vertex label or application specific data
        public LinkedList<Edge> edgesLeaving;

        public Vertex(T data) {
            this.data = data;
            this.edgesLeaving = new LinkedList<>();
        }
    }

    /**
     * Edge objects are stored within their source vertex, and group together
     * their target destination vertex, along with an integer weight.
     */
    protected class Edge {
        public Vertex target;
        public int weight;

        public Edge(Vertex target, int weight) {
            this.target = target;
            this.weight = weight;
        }
    }

    protected Hashtable<T, Vertex> vertices; // holds graph verticies, key=data

這是路徑 class

/**
     * Path objects store a discovered path of vertices and the overall distance of cost
     * of the weighted directed edges along this path. Path objects can be copied and extended
     * to include new edges and vertices using the extend constructor. In comparison to a
     * predecessor table which is sometimes used to implement Dijkstra's algorithm, this
     * eliminates the need for tracing paths backward from the destination vertex to the
     * starting vertex at the end of the algorithm.
     */
    protected class Path implements Comparable<Path> {
        public Vertex start; // first vertex within path
        public int distance; // sumed weight of all edges in path
        public List<T> dataSequence; // ordered sequence of data from vertices in path
        public Vertex end; // last vertex within path

        /**
         * Creates a new path containing a single vertex.  Since this vertex is both
         * the start and end of the path, its initial distance is zero.
         * @param start is the first vertex on this path
         */
        public Path(Vertex start) {
            this.start = start;
            this.distance = 0;
            this.dataSequence = new LinkedList<>();
            this.dataSequence.add(start.data);
            this.end = start;
        }

        /**
         * This extension constructor makes a copy of the path passed into it as an argument
         * without affecting the original path object (copyPath). The path is then extended
         * by the Edge object extendBy.
         * @param copyPath is the path that is being copied
         * @param extendBy is the edge the copied path is extended by
         */
        public Path(Path copyPath, Edge extendBy) {
            this.start = copyPath.start;
            this.start.edgesLeaving.add(extendBy);
            this.distance = extendBy.weight + copyPath.distance;
            this.dataSequence = new LinkedList<>();
            for (int i = 0; i < copyPath.dataSequence.size(); i++) {
                this.dataSequence.add(copyPath.dataSequence.get(i));
            }
            this.end = extendBy.target;
            this.dataSequence.add(end.data);
        }

        /**
         * Allows the natural ordering of paths to be increasing with path distance.
         * When path distance is equal, the string comparison of end vertex data is used to break ties.
         * @param other is the other path that is being compared to this one
         * @return -1 when this path has a smaller distance than the other,
         *         +1 when this path has a larger distance than the other,
         *         and the comparison of end vertex data in string form when these distances are tied
         */
        public int compareTo(Path other) {
            int cmp = this.distance - other.distance;
            if(cmp != 0) return cmp; // use path distance as the natural ordering
            // when path distances are equal, break ties by comparing the string
            // representation of data in the end vertex of each path
            return this.end.data.toString().compareTo(other.end.data.toString());
        }
    }

我沒有深入研究代碼,也不記得dijkstra是如何工作的,但在我看來,您沒有為類定義equalshashCode非常可疑。 我沒有找到你可以在哪里使用它,但也許我忽略了。

你也有這一行: if (front.end.data.equals(end)) {
如果T沒有equals重載,我們可能會遇到問題。 我不確定,您使用哪種類型的數據,所以它可能是也可能不是問題。

我認為問題是由Path(Path, Edge)構造函數中的this.start.edgesLeaving.add(extendBy)引起的。 在 while 循環的第一次迭代中,考慮了僅由起始頂點組成的路徑。 在 for 循環中,算法然后迭代從該路徑的結束頂點離開的所有邊,其中結束頂點和開始頂點相等。 對於這些離開邊中的每一個,都會使用Path(Path, Edge)構造函數創建一條新路徑,並且每次都會將一個新元素添加到起始頂點的edgesLeaving列表中。 這導致front.end.edgesLeaving.size()的值增長一個元素,因此執行永遠不會離開 for 循環,並且在每次迭代中, edgesLeaving增長一個,最終耗盡堆空間。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM