用Java实现Dijkstra输出指定起点到终点的最短路径

原创 2017年09月15日 21:02:26

最近在公司参加了一个比赛,其中涉及的一个问题,可以简化成如是描述:一个二维矩阵,每个点都有权重,需要找出从指定起点到终点的最短路径。

马上就想到了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;
    }
}



Dijkstra算法求最短路径(java)

任务描述:在一个无向图中,获取起始节点到所有其他节点的最短路径描述 Dijkstra(迪杰斯特拉)算法是典型的最短路径路由算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心...
  • JavaMan_chen
  • JavaMan_chen
  • 2012年12月04日 09:25
  • 46177

最短路径实现-迪杰斯特拉算法-java实现

/** * 最短路径算法:迪杰斯特拉(Dijkstra)算法 * * @author timmy1 * */public class ShortestPath { int[][] matrix;//...
  • Timmy_zzh
  • Timmy_zzh
  • 2016年11月24日 09:49
  • 1074

迪杰斯特拉求最短路径(JAVA实现)

Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。 求最短路径步骤   算法步骤如下:...
  • rookie_Algo
  • rookie_Algo
  • 2012年03月25日 12:01
  • 10418

单源最短路径( Dijkstra算法)JAVA实现

单源最短路径( Dijkstra算法)JAVA实现 package dijkstra; public class Graph { final int max=100; /* * 顶点节点...
  • Coder_py
  • Coder_py
  • 2017年05月23日 23:17
  • 374

用java编写的一个迪杰斯特拉算法(单源最短路径算法,Dijkstra算法)。

可以用于有向图和无向图。用负数表示该有向路不通。在EditPlus上写的,所以就一个.java文件。 package Test; import java.util.TreeMap; import ...
  • liuhenghui5201
  • liuhenghui5201
  • 2012年12月17日 18:42
  • 9258

单元Dijkstra算法求最短路径的的Java实现

上一篇写了无权值的最短路径的求法,是利用广度优先搜索的方法使用队列实现的,当有权值时,我们通常使用Dijkstra算法来求解最短路径的问题,这里我们假设所有的权值都是正值。 首先,在节点类改变了权值的...
  • qq_20991785
  • qq_20991785
  • 2015年03月17日 11:08
  • 865

Java 有向图的遍历,寻找所有从起点到终点的路径

最近遇到一个绘图的需求,是对地图的二次开发,在上面绘制覆盖物,所以这里涉及了对有向无环图的遍历问题。 如下图是一个有向无环图: 正常的深度优先遍历算法得到的结果会是:A、B、C、E、G、J、K、D...
  • liuwan1992
  • liuwan1992
  • 2016年12月06日 20:18
  • 5016

最短路径算法(java实现)

public class MGraph { public static final int NULL = 1000; ...
  • NEU_xiaoYu
  • NEU_xiaoYu
  • 2014年09月04日 20:32
  • 1148

数据结构 JAVA描述(八) 最短路径+拓扑排序+关键路径

最短路径迪杰斯特拉算法原文分析思路(理解不了这里就pass掉):在有向网中,从某一源点到其余各点都有一条最短路径。首先在这些最短路径中,长度最短的必定只有一条弧,且它的权值是从源点出发的所有弧上权的最...
  • liuquan0071
  • liuquan0071
  • 2015年12月31日 12:12
  • 1041

DFS求起点到终点最短路径,手动输入地图,5行4列,地图如下,起点(1,1)终点(4,3) 1是障碍 0是通路

//DFS求起点到终点最短路径,手动输入地图,5行4列,地图如下,起点(1,1)终点(4,3) 1是障碍 0是通路 //5 4 //0 0 1 0 //0 0 0 0 //0 0 1 0 //0 1 ...
  • guokaigdg
  • guokaigdg
  • 2016年04月02日 17:03
  • 408
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:用Java实现Dijkstra输出指定起点到终点的最短路径
举报原因:
原因补充:

(最多只允许输入30个字)