在上一篇漫画中,小灰介绍了单源最短路径算法 Dijkstra,没看过的小伙伴可以看下:

漫画:图的 “最短路径” 问题

漫画中我们遗留了一个问题:

如何求得最短路径的详细节点,而不仅仅是距离?

在本篇中,我们将会给与解答。

我们仍然以下面这个带权图为例,找出从顶点A到顶点G的最短距离。

详细过程如下:

第1步,创建距离表和前置顶点表。

距离表的Key是顶点名称,Value是从起点A到对应顶点的已知最短距离,默认为无穷大;前置顶点表的Key是顶点名称,Value是从起点A到对应顶点的已知最短路径的前置定点。

第2步,遍历起点A,找到起点A的邻接顶点B和C。从A到B的距离是5,从A到C的距离是2。把这一信息刷新到距离表当中。

同时,顶点B、C的前置顶点都是A,顶点A在邻接表中下标是0,所以把前置顶点表的B、C值更新为0:

第3步,从距离表中找到从A出发距离最短的点,也就是顶点C。

第4步,遍历顶点C,找到顶点C的邻接顶点D和F(A已经遍历过,不需要考虑)。从C到D的距离是6,所以A到D的距离是2+6=8;从C到F的距离是8,所以从A到F的距离是2+8=10。把这一信息刷新到表中。

同时,顶点D、F的前置顶点都是C,顶点C在邻接表中下标是2,所以把前置顶点表的D、F值更新为2:

接下来重复第3步、第4步所做的操作:

第5步,也就是第3步的重复,从距离表中找到从A出发距离最短的点(C已经遍历过,不需要考虑),也就是顶点B。

第6步,也就是第4步的重复,遍历顶点B,找到顶点B的邻接顶点D和E(A已经遍历过,不需要考虑)。从B到D的距离是1,所以A到D的距离是5+1=6,小于距离表中的8;从B到E的距离是6,所以从A到E的距离是5+6=11。把这一信息刷新到表中。

同时,顶点D、E的前置顶点都是B,顶点B在邻接表中下标是1,所以把前置顶点表的D、E值更新为1:

第7步,从距离表中找到从A出发距离最短的点(B和C不用考虑),也就是顶点D。

第8步,遍历顶点D,找到顶点D的邻接顶点E和F。从D到E的距离是1,所以A到E的距离是6+1=7,小于距离表中的11;从D到F的距离是2,所以从A到F的距离是6+2=8,小于距离表中的10。把这一信息刷新到表中。

同时,顶点E、F的前置顶点都是D,顶点D在邻接表中下标是3,所以把前置顶点表的E、F值更新为3:

第9步,从距离表中找到从A出发距离最短的点,也就是顶点E。

第10步,遍历顶点E,找到顶点E的邻接顶点G。从E到G的距离是7,所以A到G的距离是7+7=14。把这一信息刷新到表中。

同时,顶点G的前置顶点是E,顶点E在邻接表中下标是4,所以把前置顶点表的G值更新为4:

第11步,从距离表中找到从A出发距离最短的点,也就是顶点F。

第12步,遍历顶点F,找到顶点F的邻接顶点G。从F到G的距离是3,所以A到G的距离是8+3=11,小于距离表中的14。把这一信息刷新到表中:

就这样,除终点以外的全部顶点都已经遍历完毕,距离表中存储的是从起点A到所有顶点的最短距离,而前置定点存储的是从起点A到所有顶点最短路径的前置顶点。

如何把前置顶点表“翻译”成图的最短路径呢?我们可以使用回溯法,自后向前回溯:

第1步,找到图的终点G,它是最短路径的终点:

第2步,通过前置定点表找到顶点G对应的前置下标5,在顶点数组中找到下标5对应的顶点F,它是顶点G的前置顶点:

第3步,通过前置定点表找到顶点F对应的前置下标3,在顶点数组中找到下标3对应的顶点D,它是顶点F的前置顶点:

第4步,通过前置定点表找到顶点D对应的前置下标1,在顶点数组中找到下标1对应的顶点B,它是顶点D的前置顶点:

第5步,通过前置定点表找到顶点B对应的前置下标0,在顶点数组中找到下标0对应的顶点A,它是顶点B的前置顶点:

如此一来,我们把前置顶点表(0,0,1,3,3,5)转化成了最短路径(A-B-D-F-G)。

/*** Dijkstra最短路径算法*/public static int[] dijkstra(Graph graph, int startIndex) {//图的顶点数量int size = graph.vertexes.length;//创建距离表,存储从起点到每一个顶点的临时距离int[] distances = new int[size];//创建前置定点表,存储从起点到每一个顶点的已知最短路径的前置节点int[] prevs = new int[size];//记录顶点遍历状态boolean[] access = new boolean[size];//初始化最短路径表,到达每个顶点的路径代价默认为无穷大for(int i=0; i<size; i++){distances[i] = Integer.MAX_VALUE;}//遍历起点,刷新距离表access[0] = true;List<Edge> edgesFromStart = graph.adj[startIndex];for(Edge edge : edgesFromStart){distances[edge.index] = edge.weight;prevs[edge.index] = 0;}//主循环,重复 遍历最短距离顶点和刷新距离表 的操作for(int i=1; i<size; i++){//寻找最短距离顶点int minDistanceFromStart = Integer.MAX_VALUE;int minDistanceIndex = -1;for(int j=1; j<size; j++){if(!access[j] && distances[j] < minDistanceFromStart){minDistanceFromStart = distances[j];minDistanceIndex = j;}}if(minDistanceIndex == -1){break;}//遍历顶点,刷新距离表access[minDistanceIndex] = true;for(Edge edge : graph.adj[minDistanceIndex]){if(access[edge.index]){continue;}int weight = edge.weight;int preDistance = distances[edge.index];if(weight != Integer.MAX_VALUE && (minDistanceFromStart+ weight < preDistance)){distances[edge.index] = minDistanceFromStart + weight;prevs[edge.index] = minDistanceIndex;}}}return prevs;}public static void main(String[] args) {Graph graph = new Graph(7);initGraph(graph);int[] prevs = dijkstra(graph, 0);printPrevs(graph.vertexes, prevs, graph.vertexes.length-1);}private static void printPrevs(Vertex[] vertexes, int[] prev, int i){if(i>0){printPrevs(vertexes, prev, prev[i]);}System.out.println(vertexes[i].data);}/*** 图的顶点*/private static class Vertex {String data;Vertex(String data) {this.data = data;}}/*** 图的边*/private static class Edge {int index;int weight;Edge(int index, int weight) {this.index = index;this.weight = weight;}}/*** 图*/private static class Graph {private Vertex[] vertexes;private LinkedList<Edge> adj[];Graph(int size){//初始化顶点和邻接矩阵vertexes = new Vertex[size];adj = new LinkedList[size];for(int i=0; i<adj.length; i++){adj[i] = new LinkedList<Edge>();}}}private static void initGraph(Graph graph){graph.vertexes[0] = new Vertex("A");graph.vertexes[1] = new Vertex("B");graph.vertexes[2] = new Vertex("C");graph.vertexes[3] = new Vertex("D");graph.vertexes[4] = new Vertex("E");graph.vertexes[5] = new Vertex("F");graph.vertexes[6] = new Vertex("G");graph.adj[0].add(new Edge(1, 5));graph.adj[0].add(new Edge(2, 2));graph.adj[1].add(new Edge(0, 5));graph.adj[1].add(new Edge(3, 1));graph.adj[1].add(new Edge(4, 6));graph.adj[2].add(new Edge(0, 2));graph.adj[2].add(new Edge(3, 6));graph.adj[2].add(new Edge(5, 8));graph.adj[3].add(new Edge(1, 1));graph.adj[3].add(new Edge(2, 6));graph.adj[3].add(new Edge(4, 1));graph.adj[3].add(new Edge(5, 2));graph.adj[4].add(new Edge(1, 6));graph.adj[4].add(new Edge(3, 1));graph.adj[4].add(new Edge(6, 7));graph.adj[5].add(new Edge(2, 8));graph.adj[5].add(new Edge(3, 2));graph.adj[5].add(new Edge(6, 3));graph.adj[6].add(new Edge(4, 7));graph.adj[6].add(new Edge(5, 3));}

代码中,距离表和前置顶点表都是采用数组存储,这样比较方便。

输出最短路径的时候,代码中采用了递归的方式进行回溯。

漫画:Dijkstra 算法的优化相关推荐

  1. PAT甲级1003 Emergency Dijkstra算法(堆优化版/朴素版)

    前言   最近花了很多的时间在写JAVA项目上面,疏忽了算法和数据结构的学习.最近突然醒悟基础更为重要,打算从今天开始每天抽出一些时间做下PAT甲级的题目.现有题库的前两题很简单,从第三题开始吧. 题 ...

  2. 漫画:数据结构之最短路径 Dijkstra 算法的优化 | 技术头条

    作者小灰,本文经授权转载自程序员小灰(ID:chengxuyuanxiaohui). 在<漫画:图的 "最短路径" 问题>一文中小灰介绍了单源最短路径算法 Dijkst ...

  3. Dijkstra算法与其最小堆优化

    (仿佛回到了当年打比赛的时候呢 POJ 3013(Big Christmas Tree) 传送门:http://poj.org/problem?id=3013 题目大意:由一堆顶点和边构造出一棵圣诞树 ...

  4. 最短路的几种算法及其优化(模板)

    一.Dijkstra 算法 dijkstra算法适用于边权为正的情况,求单源最短路,适用于有向图和无向图 模板伪代码: 清除所有点的标号 设d[0]=0,其余d[i]=INF: 循环n次{ 在所有未标 ...

  5. matlab 流星雨,dijkstra算法及其matlab实现

    http://blog.sina.com.cn/lyqmath 简介 dijkstra算法(迪杰斯特拉算法)是一种经典的优化算法.以其应用的广泛性与简便性,值得我们去研究. Dijkstra算法是典型 ...

  6. Dijkstra算法的思想

    1. Dijkstra算法是求图中某一点到其他点的最短距路.即单源最短路径问题,该算法不能处理负权边,该算法求出的是图中某一点src,到其他所有点的最短距离. 2. 该算法的思想是将图中的点分为两类, ...

  7. 拿来就能用!Dijkstra 算法实现快递路径优化

    作者 | 李秋键 责编 | 伍杏玲 出品 | AI科技大本营(ID:rgznai100) 近几年来,快递行业发展迅猛,其中的程序设计涉及到运送路径的最优选择问题,下面我们尝试模拟实现快递路径优化问题, ...

  8. 【Dijkstra算法】未优化版+优先队列优化版

    https://blog.csdn.net/YF_Li123/article/details/74090301 Dijkstra算法伪代码://G为图:数组d为源点到达各点的最短路径长度,s为起点 D ...

  9. 最短路径——Dijkstra算法以及二叉堆优化(含证明)

    一般最短路径算法习惯性的分为两种:单源最短路径算法和全顶点之间最短路径.前者是计算出从一个点出发,到达所有其余可到达顶点的距离.后者是计算出图中所有点之间的路径距离. 单源最短路径 Dijkstra算 ...

  10. dij算法堆优化_迪杰斯特拉算法(Dijkstra) (基础dij+堆优化) BY:优少

    算法实现步骤: a.初始时,只包括源点,即S = {v},v的距离为0.U包含除v以外的其他顶点,即:U ={其余顶点},若v与U中顶点u有边,则(u,v)为正常权值,若u不是v的出边邻接点,则(u, ...

最新文章

  1. Oracle数据库查看表空间是否为自增的
  2. 基于OpenCV的焊件缺陷检测
  3. Xcode 小技巧:利用 assets 配置针对不同设备的资源
  4. R语言dataframe分组数据汇总(aggregate and sum):类似于excel的sumif函数
  5. 官方资源帖!手把手教你在TensorFlow 2.0中实现CycleGAN,推特上百赞
  6. 简单Unity时间架构设计(克洛诺斯之匙)
  7. esp32 Flash分区
  8. 《SAS编程与数据挖掘商业案例》学习笔记之八
  9. vscode+vim使用技巧
  10. 翁恺老师C语言学习笔记(十一)字符串
  11. Aizu - 1386 Starting a Scenic Railroad Service (思维乱搞)
  12. 江苏计算机类事业编总分多少,必看!江苏事业单位统考三类岗位分值分布
  13. mac苹果电脑安装非app store软件无法安装的解决办法
  14. unity connect mysql_unity连接mysql
  15. 2022-2028年中国半导体照明(LED)产业投资分析及前景预测报告(全卷)
  16. 【ExtJS6开发日记(一)】——Chart类型无法加载,及ExtJS中出现requires无法加载情况的统一说明
  17. 你必须了解的支撑研究蛋白质组学的3大技术
  18. 罗素“杀死了”康托尔
  19. 贝塔自助授权系统php源码,贝塔自助授权系统v1.1
  20. thinkpad x200 bios 超级密码破解方法

热门文章

  1. 远离魔咒,见微知著,打造崭新的罗浮宫
  2. myeclipse激活+Aptana安装配置
  3. Android APP
  4. webbrowser在vb中叫
  5. 在ASP.NET中创建安全的web站点
  6. 服务器上装的hadoop系统,在Ubuntu Server 18.04.1中安装Hadoop系统环境
  7. java string 最大长度_我说我精通字符串,面试官竟然问我Java中的String有没有长度限制!?...
  8. go任务调度2(linux的cron调用)
  9. 机器学习重塑供应链管理的10个途径
  10. 远程连接线上的mysql失败 客户端和代码连接