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

一、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实现》的图为例子。

它的邻接矩阵如下:

求解步骤 

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

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

第三步:以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}

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

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

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

三、代码实现

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

同时这是针对单源点求最短路径,如果求全图各顶点的最短路径,只需要遍历顶点然后使用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 ]

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

(0)

相关推荐

  • JS实现电话号码的字母组合算法示例

    本文实例讲述了JS实现电话号码的字母组合算法.分享给大家供大家参考,具体如下: 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合. 给出数字到字母的映射如下(与电话按键相同).注意 1 不对应任何字母. 示例: 输入:"23" 输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "c

  • JS实现的杨辉三角【帕斯卡三角形】算法示例

    本文实例讲述了JS实现的杨辉三角[帕斯卡三角形]算法.分享给大家供大家参考,具体如下: 杨辉三角,是二项式系数在三角形中的一种几何排列,在中国南宋数学家杨辉1261年所著的<详解九章算法>一书中出现. 在欧洲,帕斯卡(1623-1662)在1654年发现这一规律,所以这个表又叫做帕斯卡三角形. 帕斯卡的发现比杨辉要迟393年,比贾宪迟600年. 题目: 给定非负整数numRows,生成Pascal三角形的第一个numRows.在Pascal的三角形中,每个数字是它上面两个数字的总和. 输入:

  • JavaScript数据结构与算法之二叉树遍历算法详解【先序、中序、后序】

    本文实例讲述了JavaScript数据结构与算法之二叉树遍历算法.分享给大家供大家参考,具体如下: javascript数据结构与算法--二叉树遍历(先序) 先序遍历先访问根节点, 然后以同样方式访问左子树和右子树 代码如下: /* *二叉树中,相对较小的值保存在左节点上,较大的值保存在右节点中 * * * */ /*用来生成一个节点*/ function Node(data, left, right) { this.data = data;//节点存储的数据 this.left = left;

  • JavaScript数据结构与算法之检索算法示例【二分查找法、计算重复次数】

    本文实例讲述了JavaScript数据结构与算法之检索算法.分享给大家供大家参考,具体如下: javascript数据结构与算法---检索算法(二分查找法.计算重复次数) /*只需要查找元素是否存在数组,可以先将数组排序,再使用二分查找法*/ function qSort(arr){ if (arr.length == 0) { return []; } var left = [];//存储小于基准值 var right = [];//存储大于基准值 var pivot = arr[0]; fo

  • JavaScript数据结构与算法之检索算法实例分析【顺序查找、最大最小值、自组织查询】

    本文实例讲述了JavaScript数据结构与算法之检索算法.分享给大家供大家参考,具体如下: javascript数据结构与算法---检索算法(顺序查找.最大最小值.自组织查询) 一.顺序查找法 /* * 顺序查找法 * * 顺序查找法只要从列表的第一个元素开始循环,然后逐个与要查找的数据进行比较. * 如果匹配到了,则结束查找. * 如果到了列表的结尾也没有匹配到,那么这个数据就不存在于这个列表中. * */ function seqSearch(arr, data) { for (var i

  • JS实现的合并两个有序链表算法示例

    本文实例讲述了JS实现的合并两个有序链表算法.分享给大家供大家参考,具体如下: 将两个有序链表合并为一个新的有序链表并返回.新链表是通过拼接给定的两个链表的所有节点组成的. 示例: 输入:1->2->4, 1->3->4 输出:1->1->2->3->4->4 可以直接运行的方案: <script> function Node(element) { this.element = element;//当前节点的元素 this.next = n

  • JS实现判断有效的数独算法示例

    本文实例讲述了JS实现判断有效的数独算法.分享给大家供大家参考,具体如下: 判断一个 9x9 的数独是否有效.只需要根据以下规则,验证已经填入的数字是否有效即可. 1.数字 1-9 在每一行只能出现一次. 2.数字 1-9 在每一列只能出现一次. 3.数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次. 数独部分空格内已填入了数字,空白格用 '.' 表示. 示例 1: 输入: [ ["5","3",".",".",

  • JavaScript代码简单实现求杨辉三角给定行的最大值

    复制代码 代码如下: function cal(row) { var result = 1; for(var i = 0; i < row / 2; i++) { return result * = (row - i) / i; } return result; };

  • JavaScript实现连连看连线算法

    本文实例为大家分享了JavaScript实现连连看连线算法的多种情况,供大家参考,具体内容如下 第一种情况为两个精灵能通过一条直线连接,如下图 代码如下: var self = this; //用self变量来保存当下的这个this,以免在其他函数域中this指向不同对象而调用错误 //直线连接的两个对象 function isDirectLink(_begin,_end){ //若传入的是同一对象,连线的长度为0,返回false row col 分别表示精灵的行号和列号 if(_begin.r

  • JavaScript实现的拼图算法分析

    本文实例分析了JavaScript实现的拼图算法.分享给大家供大家参考,具体如下: 学了html5的拖拽事件,相信做出一款小小的拼图游戏也不难吧.就来说一下怎么用drag事件完成拼图游戏吧,当然html5的新方法在IE下是不兼容的.这里我把这个拼图游戏封装成一个小插件,感兴趣的话可以直接copy来用,使用方法很简单. HTML,3个div里面什么都不用写,分别是用来放拼图,参照图,拼图面吧的. <div id="selectpanel"></div> <d

随机推荐