JS使用Dijkstra算法求解最短路径


Posted in Javascript onJanuary 17, 2019

一、Dijkstra算法的思路

Dijkstra算法是针对单源点求最短路径的算法。

其主要思路如下:

1. 将顶点分为两部分:已经知道当前最短路径的顶点集合Q和无法到达顶点集合R。

2. 定义一个距离数组(distance)记录源点到各顶点的距离,下标表示顶点,元素值为距离。源点(start)到自身的距离为0,源点无法到达的顶点的距离就是一个大数(比如Infinity)。

3. 以距离数组中值为非Infinity的顶点V为中转跳点,假设V跳转至顶点W的距离加上顶点V至源点的距离还小于顶点W至源点的距离,那么就可以更新顶点W至源点的距离。即下面distance[V] + matrix[V][W] < distance[W],那么distance[W] = distance[V] + matrix[V][W]。

4. 重复上一步骤,即遍历距离数组,同时无法到达顶点集合R为空。

二、具体例子

偷个懒,直接用上一篇博客《最小生成树算法——Prim算法和Kruskal算法的JS实现》的图为例子。

JS使用Dijkstra算法求解最短路径

它的邻接矩阵如下:

JS使用Dijkstra算法求解最短路径

求解步骤 

第一步:假设源点为V0,那么目前最短路径的顶点集合Q中就只有{V0}和无法到达顶点集合R中有{V1, V2, V3, V4}

第二步:初始化distance数组,就是下面这样

JS使用Dijkstra算法求解最短路径

第三步:以distance数组中值为非Infinity的顶点为中转跳点,这一步就是V0,依照如果distance[V] + matrix[V][W] < distance[W],那么distance[W] = distance[V] + matrix[V][W]的规则,distance数组就会变成下面这样,同时集合Q变成了{V0, V1, V2, V4},集合R变成了{V3}

JS使用Dijkstra算法求解最短路径

第四步:因为集合R中还有1个顶点,所以重复第三步的方法,然后变成以V1为中转跳点,但是以V1为中转顶点都不满足distance[V] + matrix[V][W] < distance[W],所以没更新distance和两个集合

JS使用Dijkstra算法求解最短路径

第五步:因为集合R中还有1个顶点,所以重复第三步的方法,此时变成以V2为中转跳点,然后发现V0到达V3的距离可以更新,因为2 + 3 < 9,所以distance更新,集合也更新。

JS使用Dijkstra算法求解最短路径

之后同理,遍历完distance之后,输出

JS使用Dijkstra算法求解最短路径

三、代码实现

这个代码没有考虑权值为负数的情况,还没验证负数的情况,目前是按照权值为正数实现的,之后考虑完善。 

同时这是针对单源点求最短路径,如果求全图各顶点的最短路径,只需要遍历顶点然后使用Dijkstra算法,这样算上Dijkstra算法本身的时间复杂度,总的复杂度会是O(n^3)。

/**
 * Dijkstra算法:单源最短路径
 * 思路:
 * 1. 将顶点分为两部分:已经知道当前最短路径的顶点集合Q和无法到达顶点集合R。
 * 2. 定义一个距离数组(distance)记录源点到各顶点的距离,下标表示顶点,元素值为距离。源点(start)到自身的距离为0,源点无法到达的顶点的距离就是一个大数(比如Infinity)。
 * 3. 以距离数组中值为非Infinity的顶点V为中转跳点,假设V跳转至顶点W的距离加上顶点V至源点的距离还小于顶点W至源点的距离,那么就可以更新顶点W至源点的距离。即下面distance[V] + matrix[V][W] < distance[W],那么distance[W] = distance[V] + matrix[V][W]。
 * 4. 重复上一步骤,即遍历距离数组,同时无法到达顶点集合R为空。
 *
 * @param matrix 邻接矩阵,表示图
 * @param start 起点
 *
 *
 *
 * 如果求全图各顶点作为源点的全部最短路径,则遍历使用Dijkstra算法即可,不过时间复杂度就变成O(n^3)了
 * */
function Dijkstra(matrix, start = 0) {
  const rows = matrix.length,//rows和cols一样,其实就是顶点个数
    cols = matrix[0].length;
 
  if(rows !== cols || start >= rows) return new Error("邻接矩阵错误或者源点错误");
 
  //初始化distance
  const distance = new Array(rows).fill(Infinity);
  distance[start] = 0;
 
  for(let i = 0; i < rows; i++) {
    //达到不了的顶点不能作为中转跳点
    if(distance[i] < Infinity) {
      for(let j = 0; j < cols; j++) {
        //比如通过比较distance[i] + matrix[i][j]和distance[j]的大小来决定是否更新distance[j]。
        if(matrix[i][j] + distance[i] < distance[j]) {
          distance[j] = matrix[i][j] + distance[i];
        }
      }
      console.log(distance);
    }
  }
  return distance;
}
 
/**
 * 邻接矩阵
 * 值为顶点与顶点之间边的权值,0表示无自环,一个大数表示无边(比如10000)
 * */
const MAX_INTEGER = Infinity;//没有边或者有向图中无法到达
const MIN_INTEGER = 0;//没有自环
 
const matrix= [
  [MIN_INTEGER, 9, 2, MAX_INTEGER, 6],
  [9, MIN_INTEGER, 3, MAX_INTEGER, MAX_INTEGER],
  [2, 3, MIN_INTEGER, 5, MAX_INTEGER],
  [MAX_INTEGER, MAX_INTEGER, 5, MIN_INTEGER, 1],
  [6, MAX_INTEGER, MAX_INTEGER, 1, MIN_INTEGER]
];
 
 
console.log(Dijkstra(matrix, 0));//[ 0, 5, 2, 7, 6 ]

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript实现计算字符串中出现次数最多的字符和出现的次数
Mar 12 Javascript
JavaScript图片轮播代码分享
Jul 31 Javascript
jQuery事件的绑定、触发、及监听方法简单说明
May 10 Javascript
AngularJS中的DOM操作用法分析
Nov 04 Javascript
jQuery根据ID、CLASS、等获取对象的实例
Dec 04 Javascript
Bootstrap实现圆角、圆形头像和响应式图片
Dec 14 Javascript
薪资那么高的Web前端必看书单
Oct 13 Javascript
vue 插值 v-once,v-text, v-html详解
Jan 19 Javascript
如何使用less实现随机下雪动画详解
Jan 02 Javascript
JS实现滑动导航效果
Jan 14 Javascript
js+canvas实现五子棋小游戏
Aug 02 Javascript
vue element-ui中table合计指定列求和实例
Nov 02 Javascript
JavaScript简单实现的仿微博留言功能示例
Jan 17 #Javascript
vue权限管理系统的实现代码
Jan 17 #Javascript
使用nvm和nrm优化node.js工作流的方法
Jan 17 #Javascript
JS使用Prim算法和Kruskal算法实现最小生成树
Jan 17 #Javascript
微信小程序使用wxParse解析html的方法示例
Jan 17 #Javascript
nvm、nrm、npm 安装和使用详解(小结)
Jan 17 #Javascript
JavaScript之实现一个简单的Vue示例
Jan 17 #Javascript
You might like
分享PHP入门的学习方法
2007/01/02 PHP
php数组函数序列之array_intersect() 返回两个或多个数组的交集数组
2011/11/10 PHP
PHP substr 截取字符串出现乱码问题解决方法[utf8与gb2312]
2011/12/16 PHP
无需重新编译php加入ftp扩展的解决方法
2013/02/07 PHP
php动态生成函数示例
2014/03/21 PHP
php中常见的sql攻击正则表达式汇总
2014/11/06 PHP
基于JQuery.timer插件实现一个计时器
2010/04/25 Javascript
jQuery实现页面滚动时层智能浮动定位实例探讨
2013/03/29 Javascript
javascript中RegExp保留小数点后几位数的方法分享
2013/08/13 Javascript
js输出阴历、阳历、年份、月份、周示例代码
2014/01/29 Javascript
一个jquery实现的不错的多行文字图片滚动效果
2014/09/28 Javascript
详解Angular-Cli中引用第三方库
2017/05/21 Javascript
ES6 javascript中class类的get与set用法实例分析
2017/10/30 Javascript
基于vue-cli npm run build之后vendor.js文件过大的解决方法
2018/09/27 Javascript
Vue分页插件的前后端配置与使用
2019/10/09 Javascript
VuePress 中如何增加用户登录功能
2019/11/29 Javascript
[31:55]完美世界DOTA2联赛循环赛 IO vs GXR BO2第一场 11.04
2020/11/05 DOTA
详谈Python高阶函数与函数装饰器(推荐)
2017/09/30 Python
python 二分查找和快速排序实例详解
2017/10/13 Python
Python+tkinter使用40行代码实现计算器功能
2018/01/30 Python
python根据url地址下载小文件的实例
2018/12/18 Python
Django 1.10以上版本 url 配置注意事项详解
2019/08/05 Python
html5 svg 中元素点击事件添加方法
2013/01/16 HTML / CSS
伦敦一家非常流行的时尚精品店:Oxygen Boutique
2017/01/15 全球购物
美国健康和保健平台:healtop
2020/07/02 全球购物
弘扬职业精神演讲稿
2014/03/20 职场文书
请假条标准格式规范
2014/04/10 职场文书
陈安之励志演讲稿
2014/08/21 职场文书
2014村书记党建工作汇报材料
2014/11/02 职场文书
优秀教师先进事迹材料
2014/12/15 职场文书
2015年乡镇环保工作总结
2015/04/22 职场文书
党员带头倡议书
2015/04/29 职场文书
go 原生http web 服务跨域restful api的写法介绍
2021/04/27 Golang
React配置子路由的实现
2021/06/03 Javascript
Nginx四层负载均衡的配置指南
2021/06/11 Servers
springboot中的pom文件 project报错问题
2022/01/18 Java/Android