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设置FieldSet展开与收缩
May 15 Javascript
jQuery源码分析-04 选择器-Sizzle-工作原理分析
Nov 14 Javascript
Underscore.js 的模板功能介绍与应用
Dec 24 Javascript
关于JavaScript的面向对象和继承有利新手学习
Jan 11 Javascript
PHP PDO操作总结
Nov 17 Javascript
Vue.js每天必学之数据双向绑定
Sep 05 Javascript
关于Sequelize连接查询时inlude中model和association的区别详解
Feb 27 Javascript
jQuery使用DataTable实现删除数据后重新加载功能
Feb 27 Javascript
详解cordova打包成webapp的方法
Oct 18 Javascript
js tab栏切换代码实例解析
Sep 03 Javascript
JavaScript仿京东秒杀倒计时
Mar 17 Javascript
如何用JS模拟实现数组的map方法
Jul 30 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
一个简单的自动发送邮件系统(二)
2006/10/09 PHP
php中强制下载文件的代码(解决了IE下中文文件名乱码问题)
2011/05/09 PHP
通过PHP的内置函数,通过DES算法对数据加密和解密
2012/06/21 PHP
解析php扩展php_curl.dll不加载的解决方法
2013/06/26 PHP
php+html5使用FormData对象提交表单及上传图片的方法
2015/02/11 PHP
使用新浪微博API的OAuth认证发布微博实例
2015/03/27 PHP
php生成唯一数字id的方法汇总
2015/11/18 PHP
php中的抽象方法和抽象类
2017/02/14 PHP
js实现运行代码需要刷新的解决方法
2007/08/18 Javascript
三级下拉菜单的js实现代码
2011/05/23 Javascript
jQuery 重复加载错误以及修复方法
2014/12/16 Javascript
Jquery使用css方法改变样式实例
2015/05/18 Javascript
Bootstrap每天必学之表单
2015/11/23 Javascript
javascript和jquery实现用户登录验证
2016/05/04 Javascript
用director.js实现前端路由使用实例
2017/01/27 Javascript
jquery实现自适应banner焦点图
2017/02/16 Javascript
webpack配置文件和常用配置项介绍
2017/04/28 Javascript
Vue实现virtual-dom的原理简析
2017/07/10 Javascript
jQuery中的$是什么意思及 $. 和 $().的区别
2018/04/20 jQuery
JavaScript实现简单的图片切换功能(实例代码)
2020/04/10 Javascript
[42:39]老党炸弹人试玩视频
2014/09/03 DOTA
[53:10]Secret vs Pain 2018国际邀请赛小组赛BO2 第一场 8.17
2018/08/20 DOTA
pycharm+django创建一个搜索网页实例代码
2018/01/24 Python
Numpy之random函数使用学习
2019/01/29 Python
Python之Django自动实现html代码(下拉框,数据选择)
2020/03/13 Python
简单了解如何封装自己的Python包
2020/07/08 Python
Python基于xlrd模块处理合并单元格
2020/07/28 Python
专注澳大利亚特产和新西兰特产的澳洲中文网:0061澳洲制造
2019/03/24 全球购物
Diesel美国网上商店:意大利牛仔时装品牌
2020/12/10 全球购物
总务岗位职责
2013/11/19 职场文书
营业员实习自我鉴定
2013/12/07 职场文书
大学秋游活动方案
2014/02/11 职场文书
农村改厕实施方案
2014/03/22 职场文书
售后服务承诺书范文
2014/03/26 职场文书
出差报告格式模板
2014/11/06 职场文书
2019财务转正述职报告
2019/06/27 职场文书