C++最短路徑Dijkstra算法的分析與具體實(shí)現(xiàn)詳解
前言
經(jīng)典的求解最短路徑算法有這么幾種:廣度優(yōu)先算法、Dijkstra算法、Floyd算法,在此專欄中我都會(huì)將這些算法的分析與具體實(shí)現(xiàn)詳細(xì)的展現(xiàn)出來。此篇文章是對(duì) Dijkstra算法的總結(jié),該算法適用于帶權(quán)有向圖,可求出起始頂點(diǎn)到其他任意頂點(diǎn)的最小代價(jià)以及對(duì)應(yīng)路徑。
Dijkstra 算法分析
一般來說,有關(guān)圖的算法的存儲(chǔ)結(jié)構(gòu)為鄰接表、鄰接矩陣,這次就以鄰接矩陣存儲(chǔ)為例,求出下圖的最短路徑:

初始條件
需要有三個(gè)數(shù)組:
- final[]:布爾型,用來記錄頂點(diǎn)是否已找到最短路徑
- dist[]:整形,記錄最短路徑長(zhǎng)度(帶權(quán))
- path[]:整形,記錄當(dāng)前頂點(diǎn)的前驅(qū)結(jié)點(diǎn)下標(biāo)
#define MAXVERTEX 6 bool final[MAXVERTEX]; int dist[MAXVERTEX]; int path[MAXVERTEX];
對(duì)于起始頂點(diǎn)需要將final 設(shè)為true,dist 設(shè)為 0,path 設(shè)為-1
第一輪
遍歷所有與起始頂點(diǎn)相連的結(jié)點(diǎn),找到一個(gè)權(quán)值最小的邊,并將對(duì)應(yīng)頂點(diǎn) i 加入到最短路徑,即 final[i] = true,之后再遍歷與 i 相鄰的頂點(diǎn),若final 值為false 且dist 值小于dist[i]+dist[i][] 就將其dist 值更新,path 值改為 i。
第二輪及以后
第一輪結(jié)束后會(huì)有兩個(gè)頂點(diǎn)的 final 值為 true,實(shí)際上最大的循環(huán)只需要進(jìn)行n - 1次,從第一輪結(jié)束后我們從值為 false 的頂點(diǎn)中找 dist 值最小的頂點(diǎn),將其fianl 值設(shè)為 true,檢查與其相鄰頂點(diǎn)的path 值和dist 值可否更新(判斷與dist[i]+dist[i][]的大小),重復(fù)第二輪的操作直至大循環(huán)結(jié)束。這樣最終的 dist 存放的就是起始頂點(diǎn)到對(duì)應(yīng)下標(biāo)頂點(diǎn)的最短路徑長(zhǎng)度,而path 存放的就是最短路徑。
Dijkstra 代碼實(shí)現(xiàn)
#include<iostream>
using namespace std;
// 模擬實(shí)現(xiàn)Dijkstra算法,不適用于存在負(fù)值的帶權(quán)圖
#define MAXVERTEX 6
typedef struct {
char Vertex[MAXVERTEX]; //頂點(diǎn)集
int Edge[MAXVERTEX][MAXVERTEX]; // 存放權(quán)值
int vernum, arcnum; // 頂點(diǎn)數(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;
// 圖中邊權(quán)值均設(shè)為無窮大
for (int i = 0; i < G.vernum; i++) {
for (int j = 0; j < G.vernum; j++) {
G.Edge[i][j] = INT_MAX;
}
}
// 根據(jù)具體圖形設(shè)置具體權(quán)值
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; // 權(quán)值最小的邊頂點(diǎn)下標(biāo)
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的頂點(diǎn)中權(quán)值最小的頂點(diǎn)下標(biāo)
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; // 更新下標(biāo)
final[index] = true;
}
}
void print_path(MGraph G ,int v) {
cout << "對(duì)應(yīng)的最短路徑為:";
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 << "頂點(diǎn)B到頂點(diǎn)D的最小花費(fèi)為:"<< dist[3] << endl;
print_path(G, 3);
}
運(yùn)行結(jié)果:

輸入輸出格式
想得到哪個(gè)頂點(diǎn)的最短路徑就在主函數(shù)中 Dijkstra(G, ?) 第二個(gè)參數(shù)寫入下標(biāo)即可,其他對(duì)應(yīng)關(guān)系:頂點(diǎn)下標(biāo) 0~4 對(duì)應(yīng) A~E,所以在 cout那行代碼中dist下標(biāo)要與到達(dá)頂點(diǎn)一致,而出發(fā)頂點(diǎn)要與自己填入的下標(biāo)一致。
print_path 函數(shù)里的 if 語句中的下標(biāo)也要和起始頂點(diǎn)下標(biāo)一致,最后的一個(gè)cout也同樣處理
例如:
Dijkstra(G,0);
// dist[2];
cout<<"頂點(diǎn)A到頂點(diǎn)C的最短路徑為"<<dist[2]<<endl;
void print_path(MGraph G ,int v) {
cout << "對(duì)應(yīng)的最短路徑為:";
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;
}

時(shí)間復(fù)雜度
Dijkstra 算法的時(shí)間復(fù)雜度只與頂點(diǎn)有關(guān),可以通過算法分析看出來每次都要對(duì)一個(gè)頂點(diǎn)遍歷尋找與其相鄰頂點(diǎn)的最小權(quán)值,所以時(shí)間復(fù)雜度應(yīng)為:O(n2),也可以寫成O(∣V∣2),V 是頂點(diǎn)的含義(vertex)。
到此這篇關(guān)于C++最短路徑Dijkstra算法的分析與具體實(shí)現(xiàn)詳解的文章就介紹到這了,更多相關(guān)C++最短路徑Dijkstra算法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C/C++函數(shù)調(diào)用的幾種方式總結(jié)
本篇文章主要是對(duì)C/C++函數(shù)調(diào)用的幾種方式進(jìn)行了詳細(xì)的總結(jié)介紹,需要的朋友可以過來參考下,希望對(duì)大家有所幫助2013-12-12
C語言中對(duì)于循環(huán)結(jié)構(gòu)優(yōu)化的一些入門級(jí)方法簡(jiǎn)介
這篇文章主要介紹了C語言中對(duì)于循環(huán)結(jié)構(gòu)優(yōu)化的一些入門級(jí)方法,包括算法設(shè)計(jì)的改進(jìn)來提高一些并行性等方法,要的朋友可以參考下2015-12-12
window調(diào)用api列出當(dāng)前所有進(jìn)程示例
這篇文章主要介紹了window調(diào)用api列出當(dāng)前所有進(jìn)程示例,需要的朋友可以參考下2014-04-04
C語言中字符串庫函數(shù)的實(shí)現(xiàn)及模擬
C語言中有很多數(shù)據(jù)類型,比如int(整數(shù)類型)、char(字符類型)、以及浮點(diǎn)型的double(雙精度)等。但是有一點(diǎn)就是我們發(fā)現(xiàn)這里并沒有提到我們常見的有關(guān)字符串的類型。本文為大家介紹了C語言中字符串庫函數(shù)的實(shí)現(xiàn)及模擬,需要的可以參考一下2022-11-11
c++優(yōu)先隊(duì)列用法知識(shí)點(diǎn)總結(jié)
在本篇文章里小編給大家整理的是關(guān)于c++優(yōu)先隊(duì)列用法知識(shí)點(diǎn)總結(jié)內(nèi)容,需要的朋友可以參考學(xué)習(xí)下。2020-02-02
最新C/C++中的new和delete的實(shí)現(xiàn)過程小結(jié)
這篇文章主要介紹了C/C++中的new和delete的實(shí)現(xiàn)過程,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06

