Java实现Dijkstra输出最短路径的实例

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

前言:

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

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

如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望通过本文能帮助到大家,谢谢大家对本站的支持!

(0)

相关推荐

  • Java实现利用广度优先遍历(BFS)计算最短路径的方法

    本文实例讲述了Java实现利用广度优先遍历(BFS)计算最短路径的方法.分享给大家供大家参考.具体分析如下: 我们用字符串代表图的顶点(vertax),来模拟学校中Classroom, Square, Toilet, Canteen, South Gate, North Gate几个地点,然后计算任意两点之间的最短路径. 如下图所示: 如,我想从North Gate去Canteen, 程序的输出结果应为: BFS: From [North Gate] to [Canteen]: North Ga

  • java实现最短路径算法之Dijkstra算法

    前言 Dijkstra算法是最短路径算法中为人熟知的一种,是单起点全路径算法.该算法被称为是"贪心算法"的成功典范.本文接下来将尝试以最通俗的语言来介绍这个伟大的算法,并赋予java实现代码. 一.知识准备: 1.表示图的数据结构 用于存储图的数据结构有多种,本算法中笔者使用的是邻接矩阵. 图的邻接矩阵存储方式是用两个数组来表示图.一个一维数组存储图中顶点信息,一个二维数组(邻接矩阵)存储图中的边或弧的信息. 设图G有n个顶点,则邻接矩阵是一个n*n的方阵,定义为: 从上面可以看出,无

  • Java实现Dijkstra输出最短路径的实例

    Java实现Dijkstra输出指定起点到终点的最短路径 前言: 最近在公司参加了一个比赛,其中涉及的一个问题,可以简化成如是描述:一个二维矩阵,每个点都有权重,需要找出从指定起点到终点的最短路径. 马上就想到了Dijkstra算法,所以又重新温故了一遍,这里给出Java的实现. 而输出最短路径的时候,在网上也进行了查阅,没发现什么标准的方法,于是在下面的实现中,我给出了一种能够想到的比较精简的方式:利用prev[]数组进行递归输出. package graph.dijsktra; import

  • java输入数字,输出倒序的实例

    我就废话不多说了,大家还是直接看代码吧~ package c10; import java.util.Scanner; public class zhengzhengshu { public static void main(String[] args) { Scanner input = new Scanner(System.in); System.out.println("输入一个正整数:"); int num = input.nextInt(); while (num != 0)

  • java实现dijkstra最短路径寻路算法

    [引用]迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径. 它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止. 基本思想 通过Dijkstra计算图G中的最短路径时,需要指定起点s(即从顶点s开始计算). 此外,引进两个集合S和U.S的作用是记录已求出最短路径的顶点(以及相应的最短路径长度),而U则是记录还未求出最短路径的顶点(以及该顶点到起点s的距离). 初始时,S中只有起点s:U中是除s之外的顶点,并且U中顶点的路径是

  • Java利用Dijkstra和Floyd分别求取图的最短路径

    目录 1 最短路径的概述 2 杰斯特拉(Dijkstra)算法 2.1 原理 2.2 案例分析 3 弗洛伊德(Floyd)算法 3.1 原理 3.2 案例分析 4 邻接矩阵加权图实现 5 邻接表加权图实现 本文详细介绍了图的最短路径的概念,然后介绍了求最短路径的两种算法:Dijkstra算法和Floyd算法的原理,最后提供了基于邻接矩阵和邻接表的图对两种算法的Java实现. 阅读本文需要一定的图的基础,如果对于图不是太明白的可以看看这篇文章:Java数据结构之图的原理与实现. 1 最短路径的概述

  • java 实现输出随机图片实例代码

    java  实现输出随机图片实例代码 输出随机图片(CAPTCHA图像):Completely Automated Public Turing Test to Tell Computers and Humans Apart (全自动区分计算机和人类的测试) 相关主要类(JDK 查看API) BufferedImage:内存图像 Graphics:画笔 ImageIO:输出图像 放在html页面上<img src/> 注意:浏览器默认会缓存图片 public static int WIDTH =

  • Java之JFrame输出Helloworld实例

    本文实例讲述了Java之JFrame输出Helloworld的方法.分享给大家供大家参考.具体如下: JAVA的GUI程序的基本思路是以JFrame为基础,它是屏幕上window的对象,能够最大化.最小化.关闭.Swing是一个用于开发Java应用程序用户界面的开发工具包.以抽象窗口工具包(AWT)为基础使跨平台应用程序可以使用任何可插拔的外观风格.Swing开发人员只用很少的代码就可以利用Swing丰富.灵活的功能和模块化组件来创建优雅的用户界面. 说白了,你只需要很少的代码,就能利用JAVA

  • 使用java文件过滤器输出制定格式文件路径的实例代码

    使用java文件过滤器输出制定格式文件路径的实例代码如下所示: 一.使用输出路径判断过滤 import java.io.File; public class demo_file04 { public static void main(String[] args) { fileall(new File("D:\\coding")); } private static void fileall(File f1) { // System.out.println(f1); //判断文件是否是目

  • java字符串格式化输出实例讲解

    代码如果不进行格式化的处理,那么在查阅上会浪费不少的时间.今天我们要说的是字符串的格式化处理,作为基础编程内容,相信大家都字符串都不陌生.我们可以把字符串进行连接,通过这种方法实现格式化的操作.下面我们就格式化的说明.字符串符号图解.实例带来介绍. 1.说明 java 在 JDK1.5 后对 PrintStream 功能进行了扩充,增加了格式化输出功能.直接使用 Print 即可.但是输出的时候需要指定输出的数据类型. 如果不使用格式化输出,就需要进行字符串连接,如果变量比较多,拼接就会显得繁琐

  • java  实现输出随机图片实例代码

    java  实现输出随机图片实例代码 输出随机图片(CAPTCHA图像):Completely Automated Public Turing Test to Tell Computers and Humans Apart (全自动区分计算机和人类的测试) 相关主要类(JDK 查看API) BufferedImage:内存图像 Graphics:画笔 ImageIO:输出图像 放在html页面上<img src/> 注意:浏览器默认会缓存图片 public static int WIDTH =

  • Java利用Dijkstra算法求解拓扑关系最短路径

    目录 算法简介 代码实现思路 算法思想 代码示例 算法简介 迪杰斯特拉算法(Dijkstra)是由荷兰计算机科学迪家迪杰斯特拉于1959年提出的,因此又叫狄克斯特拉算法.是从一个顶点到其余各顶点最短路劲算法,解决的是有权图中最短路径问题.迪杰斯特拉算法主要特点是从起始点开始,采用贪心算法的策略,每次遍历到始点距离最近且未访问过的顶点的邻接节点,直到扩展到终点为止. 代码实现思路 1.先初始化源节点(起始点)到其他各个拓扑节点的最短距离,可以用map存放,key为节点,value为节点到源节点的距

随机推荐