C++最短路徑Dijkstra算法的分析與具體實現(xiàn)詳解
前言
經典的求解最短路徑算法有這么幾種:廣度優(yōu)先算法、Dijkstra
算法、Floyd
算法,在此專欄中我都會將這些算法的分析與具體實現(xiàn)詳細的展現(xiàn)出來。此篇文章是對 Dijkstra算法的總結,該算法適用于帶權有向圖,可求出起始頂點到其他任意頂點的最小代價以及對應路徑。
Dijkstra 算法分析
一般來說,有關圖的算法的存儲結構為鄰接表、鄰接矩陣,這次就以鄰接矩陣存儲為例,求出下圖的最短路徑:
初始條件
需要有三個數(shù)組:
- final[]:布爾型,用來記錄頂點是否已找到最短路徑
- dist[]:整形,記錄最短路徑長度(帶權)
- path[]:整形,記錄當前頂點的前驅結點下標
#define MAXVERTEX 6 bool final[MAXVERTEX]; int dist[MAXVERTEX]; int path[MAXVERTEX];
對于起始頂點需要將final 設為true,dist 設為 0,path 設為-1
第一輪
遍歷所有與起始頂點相連的結點,找到一個權值最小的邊,并將對應頂點 i 加入到最短路徑,即 final[i] = true
,之后再遍歷與 i 相鄰的頂點,若final 值為false 且dist 值小于dist[i]+dist[i][]
就將其dist 值更新,path 值改為 i。
第二輪及以后
第一輪結束后會有兩個頂點的 final 值為 true,實際上最大的循環(huán)只需要進行n - 1次,從第一輪結束后我們從值為 false 的頂點中找 dist 值最小的頂點,將其fianl 值設為 true,檢查與其相鄰頂點的path 值和dist 值可否更新(判斷與dist[i]+dist[i][]
的大小),重復第二輪的操作直至大循環(huán)結束。這樣最終的 dist 存放的就是起始頂點到對應下標頂點的最短路徑長度,而path 存放的就是最短路徑。
Dijkstra 代碼實現(xiàn)
#include<iostream> using namespace std; // 模擬實現(xiàn)Dijkstra算法,不適用于存在負值的帶權圖 #define MAXVERTEX 6 typedef struct { char Vertex[MAXVERTEX]; //頂點集 int Edge[MAXVERTEX][MAXVERTEX]; // 存放權值 int vernum, arcnum; // 頂點數(shù)和邊數(shù) }MGraph; // 初始化圖 void InitGraph(MGraph& G) { G.Vertex[0] = 'A'; G.Vertex[1] = 'B'; G.Vertex[2] = 'C'; G.Vertex[3] = 'D'; G.Vertex[4] = 'E'; G.vernum = 5; G.arcnum = 10; // 圖中邊權值均設為無窮大 for (int i = 0; i < G.vernum; i++) { for (int j = 0; j < G.vernum; j++) { G.Edge[i][j] = INT_MAX; } } // 根據(jù)具體圖形設置具體權值 G.Edge[0][1] = 10; // 諸如此類 G.Edge[0][4] = 5; G.Edge[1][2] = 1; G.Edge[1][4] = 2; G.Edge[4][1] = 3; G.Edge[2][3] = 4; G.Edge[3][2] = 6; G.Edge[4][3] = 2; G.Edge[3][0] = 7; G.Edge[4][2] = 9; } bool final[MAXVERTEX]; int dist[MAXVERTEX]; int path[MAXVERTEX]; void Dijkstra(MGraph G,int v) { for (int i = 0; i < G.vernum; i++) { final[i] = false; dist[i] = G.Edge[v][i]; path[i] = (G.Edge[v][i] == INT_MAX ? -1 : v); } final[v] = true; dist[v] = 0; // 第一輪 int index =v; // 權值最小的邊頂點下標 int para = INT_MAX; for (int j = 0; j < G.vernum; j++) { if (final[j] == false && G.Edge[v][j] < para) { para = G.Edge[v][j]; index = j; } } // 第二輪及以后 for (int i = 0; i < G.vernum; i++) { for (int c = 0; c < G.vernum; c++) { if (final[c] ==false && G.Edge[index][c] < INT_MAX) { if (G.Edge[index][c] + dist[index] < dist[c]) { dist[c] = G.Edge[index][c] + dist[index]; path[c] = index; } } } // 找到final 為false的頂點中權值最小的頂點下標 int temp = INT_MAX; int in = v; for (int i = 0; i < G.vernum; i++) { if (final[i] == false && dist[i] < temp) { temp = dist[i]; in = i; } } index = in; // 更新下標 final[index] = true; } } void print_path(MGraph G ,int v) { cout << "對應的最短路徑為:"; cout << G.Vertex[v] << "->"; for (int i = 0; i < G.vernum; i++) { if (path[v] != 1) { cout << G.Vertex[path[v]] << "->"; v = path[v]; } } cout << G.Vertex[1] << endl; } int main() { MGraph G; InitGraph(G); Dijkstra(G, 1); cout << "頂點B到頂點D的最小花費為:"<< dist[3] << endl; print_path(G, 3); }
運行結果:
輸入輸出格式
想得到哪個頂點的最短路徑就在主函數(shù)中 Dijkstra(G, ?)
第二個參數(shù)寫入下標即可,其他對應關系:頂點下標 0~4 對應 A~E
,所以在 cout
那行代碼中dist下標要與到達頂點一致,而出發(fā)頂點要與自己填入的下標一致。
print_path
函數(shù)里的 if
語句中的下標也要和起始頂點下標一致,最后的一個cout
也同樣處理
例如:
Dijkstra(G,0); // dist[2]; cout<<"頂點A到頂點C的最短路徑為"<<dist[2]<<endl; void print_path(MGraph G ,int v) { cout << "對應的最短路徑為:"; cout << G.Vertex[v] << "->"; for (int i = 0; i < G.vernum; i++) { if (path[v] != 0) { cout << G.Vertex[path[v]] << "->"; v = path[v]; } } cout << G.Vertex[0] << endl; }
時間復雜度
Dijkstra 算法的時間復雜度只與頂點有關,可以通過算法分析看出來每次都要對一個頂點遍歷尋找與其相鄰頂點的最小權值,所以時間復雜度應為:O(n2),也可以寫成O(∣V∣2),V 是頂點的含義(vertex
)。
到此這篇關于C++最短路徑Dijkstra算法的分析與具體實現(xiàn)詳解的文章就介紹到這了,更多相關C++最短路徑Dijkstra算法內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
C語言中對于循環(huán)結構優(yōu)化的一些入門級方法簡介
這篇文章主要介紹了C語言中對于循環(huán)結構優(yōu)化的一些入門級方法,包括算法設計的改進來提高一些并行性等方法,要的朋友可以參考下2015-12-12最新C/C++中的new和delete的實現(xiàn)過程小結
這篇文章主要介紹了C/C++中的new和delete的實現(xiàn)過程,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-06-06