上篇博客我们详细的介绍了两种经典的最小生成树的算法,本篇博客我们就来详细的讲一下最短路径的经典算法----迪杰斯特拉算法。首先我们先聊一下什么是最短路径,这个还是比较好理解的。比如我要从北京到济南,而从北京到济南有好多条道路,那么最短的那一条就是北京到济南的最短路径,也是我们今天要求的最短路径。

因为最短路径是基于有向图来计算的,所以我们还是使用上几篇关于图的博客中使用的示例。不过我们今天博客中用到的图是有向图,所以我们要讲上篇博客的无向图进行改造,改成有向图,然后在有向图的基础上给出最小生成树的解决方案。本篇博客我们的思路与之前数据结构相关博客的风格保持一致,首先我们先给出迪杰斯特拉算法的原理以及详细的示意图,然后根据这些示意图给出具体的实现方案。

一、迪杰斯特拉算法原理解析

在博客的第一部分,我们不谈任何与代码相关的内容,只谈迪杰斯特拉算法的原理以及生成最短路径的具体步骤。下方我们会给出迪杰斯特拉算法的计算最短路径的每一步,并给出每一步具体的说明。废话少说,进入本部分的主题。

1、有向带权图

本篇博客依然采取我们之前用的图的结构。不过我们本篇博客使用的是有向图。下方这张图就是是我们之前使用的无向图转换过来的,只是给之前的图的边添加的具体的方向,其他的并为改动。由无向图转换后的有向图如下所示,我们将在下方的图的基础上计算出从A到D的最短路径。

  

2.迪杰斯特拉算法的具体步骤

下图就是求上图中A->D的最短路径时使用迪杰斯特拉算法的具体步骤。迪杰斯特拉算法主要核心思想是由起始结点开始,慢慢的由尾结点扩散。直到扩展到尾结点位置。下方我们将根据每个步骤给出具体的介绍:

  

  • (1)与起始结点A直接相连的点是B和F, 即A->B的距离为10,A->F的距离为11, 所以我们选择A->B这个路径。

  • (2)选择B结点后,我们开始探测与B相连的结点,即A->B->G路径长度为26,A->B->I路径长度为22,A->B->C路径长度为28,这三个与上一步留下的A->F(11)相比,A->F(11)的距离最短,所以接下来要探测与F相连的结点。

  • (3)F可到达的点是G和E,所以A->F->G的距离为27,A->F->E的距离为37。因为A->F->G(27) 大于A->B->G(26)这个路径,所以由A到G的路径我们依然选择A->B->G(26)这个路径。从A->B->G(26),A->B->I(22),A->B->C(28), A->F->E(37)。中选出最短那个距离就是A->B->I(22),所以我们将I作为我们下次探测的结点。

  • (4)与I相连的就是D结点,所以我们容易计算出A->B->I->D这条路径的长度为22+21=43。从A->B->I->D(43), A->B->G(26), A->B->C(28), A->F->E(37)这些路径中我们还是选择最小的那一个,不难看出A->B->G(26)这条路径在上述路径集合中最小,所以我们将G结点作为下次路径的探测对象。

  • (5)G可到达的结点是H和D, 所以我们可以得到两条新的路径A->B->G->H(26+19=45)和A->B->G->D(26+24=50),因为A->B->G->D(50)这条路径的长度要大于A->B->I->D(43)这条路径的长度,因为这两条路径都是从A到D,所以我们选择较小的A->B->I->D(43)路径。从A->B->G->H(45),A->B->I->D(43), A->B->C(28), A->F->E(37)这几条路径中我们依然选择最小的那条路径。从上面这几条数据我们不难看出 A->B->C(28)这条路径最短,所以我们下次要探测的点是C点。

  • (6)C点可以到达的点只有D点,所以我们可以得到一条新的路径A->B->C->D, 路径长度为50。因为从A到达D的路径还有A->B->I->D(43),而A->B->C->D(50)这条路径的长度要大一些,A到D点的路径依然选择A->B->I->D(43)。C结点探测完毕,我们从A->B->G->H(45),A->B->I->D(43), A->F->E(37)几条候选路径中依然选择最小的那一个。不难看出 A->F->E(37)这条路径最小,所以下一步我们要探测E结点。

  • (7)E结点可以到达的点为H和D,所以A->F->E(37)这条路径可以延伸为A->F->E->H(44)和A->F->E->G(57)两条边。因为A到H的路径还有一条为A->B->G->H(45),而我们刚生出的这一条要小于之前的那一条,所以A到H的路径更新为A->F->E->H(44)。而A->F->E->G(57)这条A到D的路径要比A->B->I->D(43)要大,所以不进行更新,A到D的路径依然采用A->B->I->D(43)。经过这一步后我们将A->F->E->H(44)和A->B->I->D(43)进行比较,较小的路径为A->B->I->D(43),而D节点又是我们的终点,所以A到D的最短路径为A->B->I->D(43)

3、迪杰斯特拉算法的数据表示

上面是我们使用图形的方式给出了迪杰斯特拉算法的具体步骤,接下来我们会把上面的步骤转换成数据的表示方式,以便于我们使用程序进行计算。下方就是上面这些示意图的的完整的数据表示。下方矩阵中的数据标志着起始节点到该节点的距离。由上到下,以此增加距离的大小,而最上面一排的红色字母,标示着该结点的前驱。下方我们在给出每一个行数据的详细介绍。

  • 第一行数据记录了A->B和A->F的信息,当然A->A的距离为0。其他尚不可达的点为-1。

  • 第二行在第一行数据的基础上证据了A->B->C, A->B->G, A->B->I的距离信息,因为从第一行数的比较我们可以知道,A->B的距离要小于A->F的距离,所以我们的最短路径要向着A->B->?上发展。

  • 第三行的数据则是在第二行的数据上得到的,从第二行数据上我们容易看出,A->F(11)要比A->B->(C, G, I)都要小,所以我们的最短路径要向着A->F->?的放心发展。所以我们找到了A->F->E(37)和A->F->G(28)这条路径。因为A->B->G(26)小于A->F->G(28),所以A到G的路径不进行更新。

  • 第四行的数据则是第三行数据的延伸,我们可以知道A->B->I(2)在当前所有延伸的路径中最小,所以我们要向着A->B->I->? 方向发展。因此我们找到了A->B->I->D(43)这条路径。

  • 以此类推……

  

其实上图就是我们之前原理图的数据表示,接下来我们就要根据这些原理图和数据图来给出我们的代码实现,当然我们还是使用Swift语言来实现。

二、迪杰斯特拉算法的具体实现

1.上述原理总结

上面说这么多,简单的总结一下,上面整个过程无非就是下面这两步的循环,而循环结束的条件就是最短路径延伸到结束路径即可,也就是我们本例中的D点。

  • 第一步:比较已经发展的所有路径,找出目前最短的路径。

  • 第二步:在上一步找到的最短路径的基础上发展新的路径,然后重复上一步,直到延伸到end节点为止。

经过这么一分析,在给出具体的代码实现就显得简单多了,我们的程序整体上来说就是一个循环,里边包含着上面这两步。

2.具体代码实现

分析完原理后,接下来我们就要开始实现我们的代码了。下方就是我们整个代码的具体实现。当然,我们的图结构是以邻接链表的形式存储的有向联通图。具体代码实现如下所示:

(1)路径结构的存储

我们先创建一个DistanceInfo类,该类中记录了一些距离信息。previousNoteIndex字段存储的是当前节点的前驱节点的索引,默认为-1。而distance存储的就是起始结点到该节点的距离,默认是最大距离。而isInPath则标记该结点是否位于已生成路径的上,如果是的话就是true, 如果不是就是false,默认是false。

  

(2)代码的整体结    

下方代码块就是我们迪杰斯特拉算法代码实现的整体结构。首先我们会创建一个distanceInfos数组,数组中元素的个数就是图的结点的个数。其中存储的是DistanceInfo的对象,每个数组索引对应的DistanceInfo对象中存储的信息就是起始结点到该结点的距离信息。首先我们对起始结点的DistanceInfo对象进行初始化。

紧接着下方这个循环就是我们上面所说的循环,循环结束的条件就是将最短路径延伸到end结点。循环中主要有两步,第一步是在当前循环的index对应的结点上发展新的路径,第二步就是在这些发展的路径中寻找最短路径,在这个新最短路径的基础上再次发展新的路径。

  

(3)发展新的路径

接下来我们来看一下countCurrentNoteAllDistance()方法中的代码,也就是发展新的路径的代码。主要就是遍历邻接链表上当前索引所连的链表上的数据,将这些数据所对应的结点添加到我们的路径上。往路径上添加新的结点是要注意一点,比如A->D是100, 之前B->D是80,如果现在的路径要比之前的路径要大就不更新,反之就更新我们距离信息数组中的DistanceInfo对象。具体代码如下所示:

  

(4)、寻找最小路径

下方代码就是寻找当前已发展的所有路径中最短的那条路径,主要还是对DistanceInfo数组的操作。下方代码,找到最短路径后,并把最短路径的索引进行返回。

  

上方就是我们迪杰斯特拉算法代码实现的核心代码。

三、测试用例

实现完代码后,我们就要对代码进行测试了。下方就是我们的测试用例,该测试用例中创建的图是有向连通图,并且要求出节点A->D的最短路径。

  

上述测试用例的输入结果如下:

  

今天的博客就先到这儿,本篇博客所涉及的Demo也将会在github上进行分享,分享地址如下:

github分享地址:https://github.com/lizelu/DataStruct-Swift/tree/master/ShortestPathDijkstra

算法与数据结构(六) 迪杰斯特拉算法的最短路径(Swift版)的更多相关文章

  1. js图的数据结构处理---迪杰斯特拉算法

    /*//1.确定数据结构, mapf[i][j] 为点i到点j的距离 [ Infinity 2 5 Infinity Infinity Infinity Infinity 2 6 Infinity I ...

  2. C++迪杰斯特拉算法求最短路径

    一:算法历史 迪杰斯特拉算法是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法.是从一个顶点到其余各顶点的最短路径算法,解决的是有向图中最短路径问题.迪杰斯特拉算法主要特点是以 ...

  3. 图(最短路径算法————迪杰斯特拉算法和弗洛伊德算法).RP

    文转:http://blog.csdn.net/zxq2574043697/article/details/9451887 一: 最短路径算法 1. 迪杰斯特拉算法 2. 弗洛伊德算法 二: 1. 迪 ...

  4. [从今天开始修炼数据结构]图的最短路径 —— 迪杰斯特拉算法和弗洛伊德算法的详解与Java实现

    在网图和非网图中,最短路径的含义不同.非网图中边上没有权值,所谓的最短路径,其实就是两顶点之间经过的边数最少的路径:而对于网图来说,最短路径,是指两顶点之间经过的边上权值之和最少的路径,我们称路径上第 ...

  5. 数据结构---公交线路提示系统05(内附读取表格+迪杰斯特拉算法Java代码)

    今天做的最多的事情就是纠错了,通过添加输出语句判断错误来源: 找到错误来源: wb = new XSSFWorkbook(input);//语句创建错误 网上查询发现是jar包的问题: 下图为poi的 ...

  6. 迪杰斯特拉算法c语言实现

    /*http://1wangxiaobo@163.com 数据结构C语言版 迪杰斯特拉算法  P189 http://1wangxiaobo@163.com 编译环境:Dev-C++ 4.9.9.2  ...

  7. 最短路问题:迪杰斯特拉算法(Dijsktra)

    Dijkstra算法 1.定义概览 Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止.Di ...

  8. 最短路径之迪杰斯特拉算法的Java实现

    Dijkstra算法是最短路径算法中为人熟知的一种,是单起点全路径算法.该算法被称为是“贪心算法”的成功典范.本文接下来将尝试以最通俗的语言来介绍这个伟大的算法,并赋予java实现代码. 一.知识准备 ...

  9. Java 迪杰斯特拉算法实现查找最短距离

    迪杰斯特拉算法 迪杰斯特拉算法是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法.是从一个顶点到其余各顶点的最短路径算法,解决的是有向图中最短路径问题.迪杰斯特拉算法主要特点是 ...

随机推荐

  1. elasticsearch的CPU居高不下的问题

    最近项目中遇到一个令人头疼的问题,毕竟因为工作需要刚学elasticsearch,也没有去关注elasticsearch的配置问题,安装好默认把它当做数据库一样去使用,这导致接下来的项目直接挂掉... ...

  2. kafka Network

    Kafka network Processor SocketServer.Processor override def run() { startupComplete() try { while (i ...

  3. Javascript执行上下文和执行栈

    什么是执行上下文? 执行上下文就是当前JavaScript代码被解析和执行时所在环境的抽象概念,JavaScript中运行任何的代码都是在执行上下文. 什么是执行栈? 执行栈,在其他编程语言中也被叫做 ...

  4. python设计模式---结构型之代理模式

    主要想着nginx:) from abc import ABCMeta, abstractmethod # 结构型设计模式---代理模式 class Actor: def __init__(self) ...

  5. Spring 开发常见问题

    linux 下http 接收中文参数乱码 解决: 在application.yml配置文件中添加 spring: http: encoding: charset: GB2312

  6. md

    > 引用# 一级标题## 二级标题,总共六级标题 - ul + li + li 1. 1232. 456 [链接](http://www.baidu.com) ![图片](http://plac ...

  7. postgresql drop表后空间不释放

    数据库执行drop table XXX后,查看du -sh 已下降,但df -h /pgdb没有减少,是有还有进程使用对应的文件句柄 1.通过表名确认文件ID select pg_relation_f ...

  8. unity3d优化-代码篇(不定期更新)

    1.Update 大多数情况是需要在update中处理很多逻辑的,然而unity3d底层是c/c++编写,逻辑层是c#,通过monobehaviour挂载于对象中,实现一些unity3d接口的重载. ...

  9. 手把手教你从ESXI部署到vSphere web Client管理控制

    作为实验环境,一台物理机即可 既然是实验环境,那么首先把这个物理机装成ESXI6.5的宿主机并配置网络系统 第二步骤就是在ESXI上面导入OVF文件,注册一台虚机,作为数据管理中心 第三步骤就是基于这 ...

  10. json随笔

    <script> var obj2={};//这只是JS对象 var obj3={width:100,height:200};/*这跟JSON就更不沾边了,只是JS的对象 */ var o ...