用Java實現Dijkstra輸出指定起點到終點的最短路徑__java

來源:互聯網
上載者:User

最近在公司參加了一個比賽,其中涉及的一個問題,可以簡化成如是描述:一個二維矩陣,每個點都有權重,需要找出從指定起點到終點的最短路徑。

馬上就想到了Dijkstra演算法,所以又重新溫故了一遍,這裡給出Java的實現。

而輸出最短路徑的時候,在網上也進行了查閱,沒發現什麼標準的方法,於是在下面的實現中,我給出了一種能夠想到的比較精簡的方式:利用prev[]數組進行遞迴輸出。

package graph.dijsktra;import graph.model.Point;import java.util.*;/** * Created by MHX on 2017/9/13. */public class Dijkstra {    private int[][] map; // 地圖結構儲存    private int[][] edges; // 鄰接矩陣    private int[] prev; // 前驅節點標號    private boolean[] s; // S集合中存放到起點已經算出最短路徑的點    private int[] dist; // dist[i]表示起點到第i個節點的最短路徑    private int pointNum; // 點的個數    private Map<Integer, Point> indexPointMap; // 標號和點的對應關係    private Map<Point, Integer> pointIndexMap; // 點和標號的對應關係    private int v0; // 起點標號    private Point startPoint; // 起點    private Point endPoint; // 終點    private Map<Point, Point> pointPointMap; // 儲存點和權重的映射關係    private List<Point> allPoints; // 儲存所有點    private int maxX; // x座標的最大值    private int maxY; // y座標的最大值    public Dijkstra(int map[][], Point startPoint, Point endPoint) {        this.maxX = map.length;        this.maxY = map[0].length;        this.pointNum = maxX * maxY;        this.map = map;        this.startPoint = startPoint;        this.endPoint = endPoint;        init();        dijkstra();    }    /**     * 列印指定起點到終點的最短路徑     */    public void printShortestPath() {        printDijkstra(pointIndexMap.get(endPoint));    }    /**     * 初始化dijkstra     */    private void init() {        // 初始化所有變數        edges = new int[pointNum][pointNum];        prev = new int[pointNum];        s = new boolean[pointNum];        dist = new int[pointNum];        indexPointMap = new HashMap<>();        pointIndexMap = new HashMap<>();        pointPointMap = new HashMap<>();        allPoints = new ArrayList<>();        // 將map二維數組中的所有點轉換成自己的結構        int count = 0;        for (int x = 0; x < maxX; ++x) {            for (int y = 0; y < maxY; ++y) {                indexPointMap.put(count, new Point(x, y));                pointIndexMap.put(new Point(x, y), count);                count++;                allPoints.add(new Point(x, y));                pointPointMap.put(new Point(x, y), new Point(x, y, map[x][y]));            }        }        // 初始化鄰接矩陣        for (int i = 0; i < pointNum; ++i) {            for (int j = 0; j < pointNum; ++j) {                if (i == j) {                    edges[i][j] = 0;                } else {                    edges[i][j] = 9999;                }            }        }        // 根據map上的權重初始化edges,當然這種演算法是沒有單獨加起點的權重的        for (Point point : allPoints) {            for (Point aroundPoint : getAroundPoints(point)) {                edges[pointIndexMap.get(point)][pointIndexMap.get(aroundPoint)] = aroundPoint.getValue();            }        }        v0 = pointIndexMap.get(startPoint);        for (int i = 0; i < pointNum; ++i) {            dist[i] = edges[v0][i];            if (dist[i] == 9999) {                // 如果從0點(起點)到i點最短路徑是9999,即不可達                // 則i節點的前驅節點不存在                prev[i] = -1;            } else {                // 初始化i節點的前驅節點為起點,因為這個時候有最短路徑的都是與起點直接相連的點                prev[i] = v0;            }        }        dist[v0] = 0;        s[v0] = true;    }    /**     * dijkstra核心演算法     */    private void dijkstra() {        for (int i = 1; i < pointNum; ++i) { // 此時有pointNum - 1個點在U集合中,需要迴圈pointNum - 1次            int minDist = 9999;            int u = v0;            for (int j = 1; j < pointNum; ++j) { // 在U集合中,找到到起點最短距離的點                if (!s[j] && dist[j] < minDist) { // 不在S集合,就是在U集合                    u = j;                    minDist = dist[j];                }            }            s[u] = true; // 將這個點放入S集合            for (int j = 1; j < pointNum; ++j) { // 以當前剛從U集合放入S集合的點u為基礎,迴圈其可以到達的點                if (!s[j] && edges[u][j] < 9999) {                    if (dist[u] + edges[u][j] < dist[j]) {                        dist[j] = dist[u] + edges[u][j];                        prev[j] = u;                    }                }            }        }    }    private void printDijkstra(int endPointIndex) {        if (endPointIndex == v0) {            System.out.print(indexPointMap.get(v0) + ",");            return;        }        printDijkstra(prev[endPointIndex]);        System.out.print(indexPointMap.get(endPointIndex) + ",");    }    private List<Point> getAroundPoints(Point point) {        List<Point> aroundPoints = new ArrayList<>();        int x = point.getX();        int y = point.getY();        aroundPoints.add(pointPointMap.get(new Point(x - 1, y)));        aroundPoints.add(pointPointMap.get(new Point(x, y + 1)));        aroundPoints.add(pointPointMap.get(new Point(x + 1, y)));        aroundPoints.add(pointPointMap.get(new Point(x, y - 1)));        aroundPoints.removeAll(Collections.singleton(null)); // 剔除不在地圖範圍內的null點        return aroundPoints;    }    public static void main(String[] args) {        int map[][] = {                {1, 2, 2, 2, 2, 2, 2},                {1, 0, 2, 2, 0, 2, 2},                {1, 2, 0, 2, 0, 2, 2},                {1, 2, 2, 0, 2, 0, 2},                {1, 2, 2, 2, 2, 2, 2},                {1, 1, 1, 1, 1, 1, 1}        }; // 每個點都代表權重,沒有方向限制        Point startPoint = new Point(0, 3); // 起點        Point endPoint = new Point(5, 6); // 終點        Dijkstra dijkstra = new Dijkstra(map, startPoint, endPoint);        dijkstra.printShortestPath();    }}

package graph.model;public class Point {    private int x;    private int y;    private int value;    public Point(int x, int y) {        this.x = x;        this.y = y;    }    public Point(int x, int y, int value) {        this.x = x;        this.y = y;        this.value = value;    }    public int getX() {        return x;    }    public void setX(int x) {        this.x = x;    }    public int getY() {        return y;    }    public void setY(int y) {        this.y = y;    }    public int getValue() {        return value;    }    public void setValue(int value) {        this.value = value;    }    @Override    public String toString() {        return "{" +                "x=" + x +                ", y=" + y +                '}';    }    @Override    public boolean equals(Object o) {        if (this == o) return true;        if (o == null || getClass() != o.getClass()) return false;        Point point = (Point) o;        if (x != point.x) return false;        return y == point.y;    }    @Override    public int hashCode() {        int result = x;        result = 31 * result + y;        return result;    }}



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.