最短路径的概念

最短路径的问题是比较典型的应用问题。在图中,确定了起始点和终点之后,一般情况下都可以有很多条路径来连接两者。而边或弧的权值最小的那一条路径就称为两点之间的最短路径,路径上的第一个顶点为源点,最后一个顶点为终点。

图的最短路径的算法有很多,本文主要介绍狄克斯特拉(Dijkstra)提出的一种按照长度递增的次序产生的最短路径的算法

Dijkstra算法介绍

Dijkstra算法的特点

Dijkstra算法使用了广度优先搜索解决赋权有向图或者无向图的单源最短路径问题,算法最终得到一个最短路径树。该算法常用于路由算法或者作为其他图算法的一个子模块。

该算法的时间复杂度是n的平方,可以使用堆优化。

但是,要注意一点,Dijkstra算法只能适用于权值为正的情况下;如果权值存在负数,则不能使用。

Dijkstra算法的思想

  1. 设置两个顶点集S和T,集合S中存放已经找到最短路径的顶点,集合T中存放着当前还未找到最短路径的顶点;
  2. 初始状态下,集合S中只包含源点V1,T中为除了源点之外的其余顶点,此时源点到各顶点的最短路径为两个顶点所连的边上的权值,如果源点V1到该顶点没有边,则最小路径为无穷大;
  3. 从集合T中选取到源点V1的路径长度最短的顶点Vi加入到集合S中;
  4. 修改源点V1到集合T中剩余顶点Vj的最短路径长度。新的最短路径长度值为Vj原来的最短路径长度值与顶点Vi的最短路径长度加上Vi到Vj的路径长度值中的较小者;
  5. 不断重复步骤3、4,直至集合T的顶点全部加入到集合S中。

Dijkstra算法的实例演示

下面求下图,从源点v1到其他各个顶点的最短路径:

首先第一步,我们先声明一个dis数组(这是一个距离数组,用于记录各点距离源点的距离),该数组初始化的值为:

我们的顶点集T的初始化为:T={v1}。

既然是求 v1顶点到其余各个顶点的最短路程,那就先找一个离 1 号顶点最近的顶点。通过数组 dis 可知当前离v1顶点最近是 v3顶点。当选择了 2 号顶点后,dis[2](下标从0开始)的值就已经从“估计值”变为了“确定值”,即 v1顶点到 v3顶点的最短路程就是当前 dis[2]值。将V3加入到T中。

为什么呢?因为目前离 v1顶点最近的是 v3顶点,并且这个图所有的边都是正数,那么肯定不可能通过第三个顶点中转,使得 v1顶点到 v3顶点的路程进一步缩短了。因为 v1顶点到其它顶点的路程肯定没有 v1到 v3顶点短。

OK,既然确定了一个顶点的最短路径,下面我们就要根据这个新入的顶点V3会有出度,发现以v3 为弧尾的有: < v3,v4 >,那么我们看看路径:v1–v3–v4的长度是否比v1–v4短,其实这个已经是很明显的了,因为dis[3]代表的就是v1–v4的长度为无穷大,而v1–v3–v4的长度为:10+50=60,所以更新dis[3]的值,得到如下结果:

因此 dis[3]要更新为 60。这个过程有个专业术语叫做“松弛”。即 v1顶点到 v4顶点的路程即 dis[3],通过 < v3,v4> 这条边松弛成功。这便是 Dijkstra 算法的主要思想:通过“边”来松弛v1顶点到其余各个顶点的路程。

然后,我们又从除dis[2]和dis[0]外的其他值中寻找最小值,发现dis[4]的值最小,通过之前是解释的原理,可以知道v1到v5的最短距离就是dis[4]的值,然后,我们把v5加入到集合T中,然后,考虑v5的出度是否会影响我们的数组dis的值,v5有两条出度:< v5,v4>和 < v5,v6>,然后我们发现:v1–v5–v4的长度为:50,而dis[3]的值为60,所以我们要更新dis[3]的值.另外,v1-v5-v6的长度为:90,而dis[5]为100,所以我们需要更新dis[5]的值。更新后的dis数组如下图:

然后,继续从dis中选择未确定的顶点的值中选择一个最小的值,发现dis[3]的值是最小的,所以把v4加入到集合T中,此时集合T={v1,v3,v5,v4},然后,考虑v4的出度是否会影响我们的数组dis的值,v4有一条出度:< v4,v6>,然后我们发现:v1–v5–v4–v6的长度为:60,而dis[5]的值为90,所以我们要更新dis[5]的值,更新后的dis数组如下图:

然后,我们使用同样原理,分别确定了v6和v2的最短路径,最后dis的数组的值如下:

因此,从图中,我们可以发现v1-v2的值为:∞,代表没有路径从v1到达v2。所以我们得到的最后的结果为:

起点  终点    最短路径    长度
v1    v2     无          ∞    v3     {v1,v3}    10v4     {v1,v5,v4}  50v5     {v1,v5}    30v6     {v1,v5,v4,v6} 60

由此分析下来,我们可以得到以下几点:

1、需要设立两个数组,一个数组为diatance,用于存放个顶点距离源点的距离;另一个数组为st,用于判断顶点是在哪一个集合内(true为在S集合,false为在T集合内)。

2、Dijkstra算法的精髓:

  • 每次循环都将T集合内距离源点最近的那个点加入到S集合中,且加入的那个点距离源点的距离由“最短距离估计值”转变成“最短距离准确值”;
  • 每次循环添加一个点到S集合中后,会导致与加入的那个点相邻的顶点可能会发生距离的更新,也就是“最短距离估计值”的更新。更新方法是取原本的“最短距离估计值”与新加入的那个点的“最短距离确定值”+新加入的那个点与其邻点的距离的较小者。
  • “最短距离估计值”的真正内涵:其实可以把S集合看成一个黑箱子,“最短距离估计值”就是该顶点经过黑箱子里的各个点到源点的最短距离,但不能保证该顶点是否可以通过黑箱子外(T集合)的顶点绕路达到更短。只有每次循环中“最短距离估计值”中的最小值,才能确定为“最短距离确定值”加入到集合S。

Dijkstra算法的Java代码实现

基于邻接矩阵的代码实现:

 public int[] dijkstra(int v) {if (v < 0 || v >= numOfVexs)throw new ArrayIndexOutOfBoundsException();boolean[] st = new boolean[numOfVexs];// 默认初始为falseint[] distance = new int[numOfVexs];// 存放源点到其他点的矩离for (int i = 0; i < numOfVexs; i++)for (int j = i + 1; j < numOfVexs; j++) {if (edges[i][j] == 0) {edges[i][j] = Integer.MAX_VALUE;edges[j][i] = Integer.MAX_VALUE;}}for (int i = 0; i < numOfVexs; i++) {distance[i] = edges[v][i];}st[v] = true;// 处理从源点到其余顶点的最短路径for (int i = 0; i < numOfVexs; ++i) {int min = Integer.MAX_VALUE;int index=-1;// 比较从源点到其余顶点的路径长度for (int j = 0; j < numOfVexs; ++j) {// 从源点到j顶点的最短路径还没有找到if (st[j]==false) {// 从源点到j顶点的路径长度最小if (distance[j] < min) {index = j;min = distance[j];}}}//找到源点到索引为index顶点的最短路径长度if(index!=-1)st[index] = true;// 更新当前最短路径及距离for (int w = 0; w < numOfVexs; w++)if (st[w] == false) {if (edges[index][w] != Integer.MAX_VALUE&& (min + edges[index][w] < distance[w]))distance[w] = min + edges[index][w];}}return distance;}

基于邻接表的代码实现:

 public int[] dijkstra(int v) {if (v < 0 || v >= numOfVexs)throw new ArrayIndexOutOfBoundsException();boolean[] st = new boolean[numOfVexs];// 默认初始为falseint[] distance = new int[numOfVexs];// 存放源点到其他点的距离for (int i = 0; i < numOfVexs; i++) {distance[i] = Integer.MAX_VALUE;}ENode current;current = vexs[v].firstadj;while (current != null) {distance[current.adjvex] = current.weight;current = current.nextadj;}distance[v] = 0;st[v] = true;// 处理从源点到其余顶点的最短路径for (int i = 0; i < numOfVexs; i++) {int min = Integer.MAX_VALUE;int index = -1;// 比较从源点到其余顶点的路径长度for (int j = 0; j < numOfVexs; j++) {// 从源点到j顶点的最短路径还没有找到if (st[j] == false) {// 从源点到j顶点的路径长度最小if (distance[j] < min) {index = j;min = distance[j];}}}// 找到源点到索引为index顶点的最短路径长度if (index != -1)st[index] = true;// 更新当前最短路径及距离for (int w = 0; w < numOfVexs; w++)if (st[w] == false) {current = vexs[w].firstadj;while (current != null) {if (current.adjvex == index)if ((min + current.weight) < distance[w]) {distance[w] = min + current.weight;break;}current = current.nextadj;}}}return distance;}

关于算法程序的两点说明:

  1. 这边方法一个参数是表明了源点的位置,方法的内部会找出从源点到图中每个点的路径最小值;
  2. 这边的其他的主要部分(如成员变量的定义等),参考【数据结构】图(邻接矩阵、邻接表)的JAVA代码实现。

【数据结构】图(最短路径Dijkstra算法)的JAVA代码实现相关推荐

  1. 最短路径 Dijkstra算法的Matlab代码实现

    为了搞清楚最短路径的算法过程,自己编写代码实现dijkstra算法寻找路径 % 文件名:dijkstra.m % 时间:2020年9月12日 % 来源:https://blog.csdn.net/li ...

  2. 数据结构——图——最短路径DF算法

    一.Dijkstra算法(贪心地求最短距离的算法) 在此算法中,我按照自己的理解去命名,理解起来会轻松一些. #define MAXSIZE 100 #define UNVISITED 0 #defi ...

  3. 【数据结构与算法】带权图最短路径Dijkstra算法

    伪代码 //u是源节点 Initialization: N' = {u} for all nodes v if v is a neighbor of u then D(v) = c(u,v) e1se ...

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

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

  5. 最短路径——Dijkstra算法与Floyd算法

    最短路径 Dijkstra算法 C语言代码实现 代码解析 Floyd算法 算法解析 C语言代码实现 最短路径问题 最短路径问题是我们经常会面临的一种决策问题.在图论中,非网图(边没有权值)的最短路径就 ...

  6. python棋盘最短路径_Python数据结构与算法之图的最短路径(Dijkstra算法)完整实例...

    本文实例讲述了Python数据结构与算法之图的最短路径(Dijkstra算法).分享给大家供大家参考,具体如下: # coding:utf-8 # Dijkstra算法--通过边实现松弛 # 指定一个 ...

  7. 最短路径-Dijkstra算法与Floyd算法

    最短路径-Dijkstra算法与Floyd算法 原文:https://www.cnblogs.com/smile233/p/8303673.html 一.最短路径 ①在非网图中,最短路径是指两顶点之间 ...

  8. Python 中的图:Dijkstra 算法

    介绍   图是最有用的数据结构之一.它们可用于对几乎所有事物进行建模--对象关系和网络是最常见的.图像可以表示为网格状的像素图,句子可以表示为单词的图.图表被用于各个领域,从制图到社会心理学,当然它们 ...

  9. 对一致性Hash算法,Java代码实现的深入研究

    一致性Hash算法 关于一致性Hash算法,在我之前的博文中已经有多次提到了,MemCache超详细解读一文中"一致性Hash算法"部分,对于为什么要使用一致性Hash算法.一致性 ...

最新文章

  1. 计算机编辑功能在哪,注册表编辑器怎么打开-电脑的剪切板在哪里 电脑剪切板里面的内容怎么修改...
  2. 学习笔记Hive(八)—— 查询优化
  3. PHP-Wakeup魔术漏洞骚操作
  4. Unity 编译apk启动出异常
  5. 移动端不利用HTML5和echarts开发一样可以实现大数据展示及炫酷统计系统(产品技术综合)...
  6. 十五. Python基础(15)--内置函数-1
  7. MFC中CString类字符串用法小结
  8. 19-20年月度行业分析
  9. 王树尧老师运筹学课程笔记 07 线性规划与单纯形法(标准型、基、基解、基可行解、可行基)
  10. aida64怎么测试cpu稳定性_怎么测试电脑CPU稳定性
  11. 如何下载石家庄市卫星地图高清版大图
  12. 目标跟踪(二):拓展卡尔曼滤波(EKF)
  13. 阿里的花名,是要抹去员工独立人格?
  14. codewars练习(javascript)-2021/2/18
  15. 【ansible】如何将ansible jinja2的双花括号转义?
  16. Qt--ipad滑屏效果
  17. Mac下Android studio搭建Android开发环境【新手】
  18. “创新实践”项目介绍2:《3D点云中的汽车检测》
  19. VS2015 还是VS2017 好用_强烈推荐:2020年12款Visual Studio 好用的工具
  20. 基于PyQt的分组工具

热门文章

  1. 2019年创业做什么有前景?
  2. ipad html兼容问题,如何处理ipad safari CSS 样式的兼容性?_html/css_WEB-ITnose
  3. 【Redis】数据结构的应用——GEO 【搜索“附近的餐馆”、在打车软件上叫车】
  4. jQuery+PHP+Ajax动态数字统计展示实例
  5. FEC【筷云早报】2020年3月16日星期一
  6. HTML5期末大作业——布卡漫画官网(4个页面)HTML+CSS+JavaScript
  7. 对计算机课的期待200字,谈《计算机应用》课程教学组织优化
  8. 汇编:动态画出一棵七彩圣诞树
  9. word文档中插入图片显示不全解决办法
  10. 默默学Sharding-Sphere(二)