1. 程式人生 > >圖的最短路徑-Dijkstra演算法和Floyd演算法

圖的最短路徑-Dijkstra演算法和Floyd演算法

Dijkstra演算法

單源點最短路徑問題

Dijkstra演算法主要用來解決單源點最短路徑問題。

給定帶權有向圖G=(V,E),其中每條邊的權是非負數。另外,還給定V中的一個頂點,稱為源。現在要計算從源到所有其他各頂點的最短路徑長度,這裡路徑的長度是指路徑上各邊權之和。這個問題通常稱為單源最短路徑問題(Single-Source Shortest Paths)。

應用例項——計算機網路傳輸:怎樣找到一種最經濟的方式,從一臺計算機向網上所有其它計算機發送一條訊息。

思想

設定一個集合S存放已經找到最短路徑的頂點,S的初始狀態只包含源點v,對vi∈V-S,假設從源點v到vi的有向邊為最短路徑。以後每求得一條最短路徑v, …, vk,就將vk加入集合S中,並將路徑v, …, vk , vi與原來的假設相比較,取路徑長度較小者為最短路徑。重複上述過程,直到集合V中全部頂點加入到集合S中。

資料結構
圖的儲存結構:帶權的鄰接矩陣。
陣列distance[n]:每個distance[i]記錄源點到各頂點的最小距離。

例:
在這裡插入圖片描述
它的鄰接矩陣:
在這裡插入圖片描述
第一步:假設源點為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之後,輸出

程式碼

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]
];

Floyd演算法

主要用於解決任意兩點間最短路徑問題的演算法。

思想

對於從vi到vj的弧,進行n次試探:首先考慮路徑vi,v0,vj是否存在,如果存在,則比較vi,vj和vi,v0,vj的路徑長度,取較短者為從vi到vj的中間頂點的序號不大於0的最短路徑。在路徑上再增加一個頂點v1,依此類推,在經過n次比較後,最後求得的必是從頂點vi到頂點vj的最短路徑。