JS使用Dijkstra算法求解最短路徑
一、Dijkstra算法的思路
Dijkstra算法是針對(duì)單源點(diǎn)求最短路徑的算法。
其主要思路如下:
1. 將頂點(diǎn)分為兩部分:已經(jīng)知道當(dāng)前最短路徑的頂點(diǎn)集合Q和無(wú)法到達(dá)頂點(diǎn)集合R。
2. 定義一個(gè)距離數(shù)組(distance)記錄源點(diǎn)到各頂點(diǎn)的距離,下標(biāo)表示頂點(diǎn),元素值為距離。源點(diǎn)(start)到自身的距離為0,源點(diǎn)無(wú)法到達(dá)的頂點(diǎn)的距離就是一個(gè)大數(shù)(比如Infinity)。
3. 以距離數(shù)組中值為非Infinity的頂點(diǎn)V為中轉(zhuǎn)跳點(diǎn),假設(shè)V跳轉(zhuǎn)至頂點(diǎn)W的距離加上頂點(diǎn)V至源點(diǎn)的距離還小于頂點(diǎn)W至源點(diǎn)的距離,那么就可以更新頂點(diǎn)W至源點(diǎn)的距離。即下面distance[V] + matrix[V][W] < distance[W],那么distance[W] = distance[V] + matrix[V][W]。
4. 重復(fù)上一步驟,即遍歷距離數(shù)組,同時(shí)無(wú)法到達(dá)頂點(diǎn)集合R為空。
二、具體例子
偷個(gè)懶,直接用上一篇博客《最小生成樹(shù)算法——Prim算法和Kruskal算法的JS實(shí)現(xiàn)》的圖為例子。
它的鄰接矩陣如下:
求解步驟
第一步:假設(shè)源點(diǎn)為V0,那么目前最短路徑的頂點(diǎn)集合Q中就只有{V0}和無(wú)法到達(dá)頂點(diǎn)集合R中有{V1, V2, V3, V4}
第二步:初始化distance數(shù)組,就是下面這樣
第三步:以distance數(shù)組中值為非Infinity的頂點(diǎn)為中轉(zhuǎn)跳點(diǎn),這一步就是V0,依照如果distance[V] + matrix[V][W] < distance[W],那么distance[W] = distance[V] + matrix[V][W]的規(guī)則,distance數(shù)組就會(huì)變成下面這樣,同時(shí)集合Q變成了{(lán)V0, V1, V2, V4},集合R變成了{(lán)V3}
第四步:因?yàn)榧蟁中還有1個(gè)頂點(diǎn),所以重復(fù)第三步的方法,然后變成以V1為中轉(zhuǎn)跳點(diǎn),但是以V1為中轉(zhuǎn)頂點(diǎn)都不滿足distance[V] + matrix[V][W] < distance[W],所以沒(méi)更新distance和兩個(gè)集合
第五步:因?yàn)榧蟁中還有1個(gè)頂點(diǎn),所以重復(fù)第三步的方法,此時(shí)變成以V2為中轉(zhuǎn)跳點(diǎn),然后發(fā)現(xiàn)V0到達(dá)V3的距離可以更新,因?yàn)? + 3 < 9,所以distance更新,集合也更新。
之后同理,遍歷完distance之后,輸出
三、代碼實(shí)現(xiàn)
這個(gè)代碼沒(méi)有考慮權(quán)值為負(fù)數(shù)的情況,還沒(méi)驗(yàn)證負(fù)數(shù)的情況,目前是按照權(quán)值為正數(shù)實(shí)現(xiàn)的,之后考慮完善。
同時(shí)這是針對(duì)單源點(diǎn)求最短路徑,如果求全圖各頂點(diǎn)的最短路徑,只需要遍歷頂點(diǎn)然后使用Dijkstra算法,這樣算上Dijkstra算法本身的時(shí)間復(fù)雜度,總的復(fù)雜度會(huì)是O(n^3)。
/** * Dijkstra算法:?jiǎn)卧醋疃搪窂? * 思路: * 1. 將頂點(diǎn)分為兩部分:已經(jīng)知道當(dāng)前最短路徑的頂點(diǎn)集合Q和無(wú)法到達(dá)頂點(diǎn)集合R。 * 2. 定義一個(gè)距離數(shù)組(distance)記錄源點(diǎn)到各頂點(diǎn)的距離,下標(biāo)表示頂點(diǎn),元素值為距離。源點(diǎn)(start)到自身的距離為0,源點(diǎn)無(wú)法到達(dá)的頂點(diǎn)的距離就是一個(gè)大數(shù)(比如Infinity)。 * 3. 以距離數(shù)組中值為非Infinity的頂點(diǎn)V為中轉(zhuǎn)跳點(diǎn),假設(shè)V跳轉(zhuǎn)至頂點(diǎn)W的距離加上頂點(diǎn)V至源點(diǎn)的距離還小于頂點(diǎn)W至源點(diǎn)的距離,那么就可以更新頂點(diǎn)W至源點(diǎn)的距離。即下面distance[V] + matrix[V][W] < distance[W],那么distance[W] = distance[V] + matrix[V][W]。 * 4. 重復(fù)上一步驟,即遍歷距離數(shù)組,同時(shí)無(wú)法到達(dá)頂點(diǎn)集合R為空。 * * @param matrix 鄰接矩陣,表示圖 * @param start 起點(diǎn) * * * * 如果求全圖各頂點(diǎn)作為源點(diǎn)的全部最短路徑,則遍歷使用Dijkstra算法即可,不過(guò)時(shí)間復(fù)雜度就變成O(n^3)了 * */ function Dijkstra(matrix, start = 0) { const rows = matrix.length,//rows和cols一樣,其實(shí)就是頂點(diǎn)個(gè)數(shù) cols = matrix[0].length; if(rows !== cols || start >= rows) return new Error("鄰接矩陣錯(cuò)誤或者源點(diǎn)錯(cuò)誤"); //初始化distance const distance = new Array(rows).fill(Infinity); distance[start] = 0; for(let i = 0; i < rows; i++) { //達(dá)到不了的頂點(diǎn)不能作為中轉(zhuǎn)跳點(diǎn) if(distance[i] < Infinity) { for(let j = 0; j < cols; j++) { //比如通過(guò)比較distance[i] + matrix[i][j]和distance[j]的大小來(lái)決定是否更新distance[j]。 if(matrix[i][j] + distance[i] < distance[j]) { distance[j] = matrix[i][j] + distance[i]; } } console.log(distance); } } return distance; } /** * 鄰接矩陣 * 值為頂點(diǎn)與頂點(diǎn)之間邊的權(quán)值,0表示無(wú)自環(huán),一個(gè)大數(shù)表示無(wú)邊(比如10000) * */ const MAX_INTEGER = Infinity;//沒(méi)有邊或者有向圖中無(wú)法到達(dá) const MIN_INTEGER = 0;//沒(méi)有自環(huán) 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 ]
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- javascript算法題 求任意一個(gè)1-9位不重復(fù)的N位數(shù)在該組合中的大小排列序號(hào)
- javascript算法題:求任意一個(gè)1-9位不重復(fù)的N位數(shù)在該組合中的大小排列序號(hào)
- JavaScript求一組數(shù)的最小公倍數(shù)和最大公約數(shù)常用算法詳解【面向?qū)ο螅貧w迭代和循環(huán)】
- javascript使用遞歸算法求兩個(gè)數(shù)字組合功能示例
- JavaScript實(shí)現(xiàn)數(shù)組全排列、去重及求最大值算法示例
- javascript中解析四則運(yùn)算表達(dá)式的算法和示例
- JS使用Prim算法和Kruskal算法實(shí)現(xiàn)最小生成樹(shù)
- JS實(shí)現(xiàn)計(jì)算小于非負(fù)數(shù)n的素?cái)?shù)的數(shù)量算法示例
- JavaScript采用遞歸算法計(jì)算階乘實(shí)例
- JavaScript實(shí)現(xiàn)的一個(gè)計(jì)算數(shù)字步數(shù)的算法分享
- JS求解兩數(shù)之和算法詳解
相關(guān)文章
bootstrap3使用bootstrap datetimepicker日期插件
這篇文章主要為大家詳細(xì)介紹了bootstrap3中使用bootstrap datetimepicker日期插件的用法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05基于prototype擴(kuò)展的JavaScript常用函數(shù)庫(kù)
基于prototype擴(kuò)展的JavaScript常用函數(shù)庫(kù)實(shí)現(xiàn)代碼,學(xué)習(xí)js的朋友可以參考下。2010-11-11微信網(wǎng)頁(yè)登錄邏輯與實(shí)現(xiàn)方法
這篇文章主要介紹了微信網(wǎng)頁(yè)登錄邏輯與實(shí)現(xiàn)方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-04-04詳解Bootstrap創(chuàng)建表單的三種格式(一)
在本章中,我們將學(xué)習(xí)如何使用 Bootstrap 創(chuàng)建表單。Bootstrap 通過(guò)一些簡(jiǎn)單的 HTML 標(biāo)簽和擴(kuò)展的類即可創(chuàng)建出不同樣式的表單,對(duì)bootstrap 表單相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)吧2016-01-01微信小程序如何實(shí)現(xiàn)radio單選框單擊打勾和取消
這篇文章主要介紹了微信小程序如何實(shí)現(xiàn)radio單選框單擊打勾和取消,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-01-01JQuery入門(mén)——用one()方法綁定事件處理函數(shù)(僅觸發(fā)一次)
one()方法功能是為所選的元素綁定一個(gè)僅觸發(fā)一次的處理函數(shù),感興趣的朋友可以了解下它的調(diào)用語(yǔ)法為:one(type, [data], fn),閱讀本文或許有意外的收獲呢2013-02-02ES6 proxy和reflect的使用方法與應(yīng)用實(shí)例分析
這篇文章主要介紹了ES6 proxy和reflect的使用方法,結(jié)合具體實(shí)例形式分析了ES6 proxy和reflect基本功能、原理、使用方法與操作注意事項(xiàng),需要的朋友可以參考下2020-02-02