1. 程式人生 > >單源最短路徑—Dijkstra演算法(C++)

單源最短路徑—Dijkstra演算法(C++)

最近複習圖演算法,練練手
先拿Dijkstra演算法開刀吧

以下是C++程式碼

包含:Dijkstra演算法函式(返回源節點到其餘節點之間的最短路徑)、路徑列印輸出函式

PS:本人只喜歡用vector,不喜歡用原生陣列;只喜歡string,不喜歡char*、char[]什麼亂七八糟的。

#include <iostream>
#include <vector>

using namespace std;

typedef int DATA_TYPE;  // 權值為int型
const DATA_TYPE NO_EDGE = 10000000;  // 表示沒有該邊

// 圖的結構體定義
struct MatrixGraph { vector<vector<DATA_TYPE> > weights; int vertexNum; // 其實定義了鄰接矩陣,這個也可以省 }; // 路徑格式轉換(從點對連結式轉換到序列式) vector<int> getVisitPath(vector<int> path, int startNode, int endNode) { vector<int> visitPath; visitPath.push_back(endNode); if (path[endNode] != -1
) { while (path[endNode] != startNode) { visitPath.insert(visitPath.begin(), path[endNode]); endNode = path[endNode]; } } visitPath.insert(visitPath.begin(), startNode); return visitPath; } // 輸出各條最短路徑 void displayPath(vector<DATA_TYPE>
distance, vector<int> path, int startNode) { for (size_t i = 0; i < path.size(); ++i) { // 排除自己和自己 以及 不可達的路徑 if (i != startNode && distance[i] < NO_EDGE) { vector<int> visitPath = getVisitPath(path, startNode, i); cout << "From " << visitPath[0] << " to " << visitPath[visitPath.size() - 1] << "|| "; cout << "Distance: " << distance[i] << " || Path: "; for (size_t j = 0; j < visitPath.size() - 1; ++j) { cout << visitPath[j] << "->"; } cout << visitPath[visitPath.size() - 1] << endl; } } } // Dijkstra演算法 vector<DATA_TYPE> dijkstra(vector<vector<DATA_TYPE> > weights, int startNode) { vector<DATA_TYPE> distance; // 從源節點到其餘各個節點的最短路徑陣列 vector<int> path; // 訪問路徑(點對) vector<int> S; // 已訪問的 DATA_TYPE minDistance; // 單次迴圈的最小值 int vertexNum = weights.size(); for (size_t i = 0; i < vertexNum; ++i) { // 最短路徑初始化 distance.push_back(weights[startNode][i]); // 已訪問標記陣列初始化 S.push_back(0); // 0表示未訪問 // 路徑初始化 if (weights[startNode][i] != NO_EDGE) path.push_back(startNode); // 可達 else path.push_back(-1); // 不可達記為-1 } S[startNode] = 1; // 源節點放入S中 path[startNode] = startNode; // 路徑開始為startNode 該值可隨意 size_t k; // 最近頂點 for (size_t i = 0; i < vertexNum; ++i) { minDistance = NO_EDGE; for (size_t j = 0; j < vertexNum; ++j) { if ((S[j] == 0) && (distance[j] < minDistance)) { k = j; minDistance = distance[j]; } } S[k] = 1; // 最小 則將頂點k加入S for (size_t j = 0; j < vertexNum; ++j) { if (S[j] == 0) { // 對於所有與k相鄰的節點(即可從k到達這些節點) if ((weights[k][j] < NO_EDGE) && (distance[k] + weights[k][j] < distance[j])) { // 若新路徑的長度小於最初判斷時的長度,則更新 distance[j] = distance[k] + weights[k][j]; path[j] = k; // 新增k到路徑中 } } } } // 輸出路徑情況 displayPath(distance, path, startNode); return distance; } int main() { // 圖的初始化 // 頂點編號必須為從0開始的連續的整數(若不是,先轉換) // 圖為有向圖 MatrixGraph graph; graph.vertexNum = 7; // 定義了鄰接矩陣 這個可以省 graph.weights.push_back(vector<DATA_TYPE>{0, 4, 6, 6, NO_EDGE, NO_EDGE, NO_EDGE}); graph.weights.push_back(vector<DATA_TYPE>{NO_EDGE, 0, 1, NO_EDGE, 7, NO_EDGE, NO_EDGE}); graph.weights.push_back(vector<DATA_TYPE>{NO_EDGE, NO_EDGE, 0, NO_EDGE, 6, 4, NO_EDGE}); graph.weights.push_back(vector<DATA_TYPE>{NO_EDGE, NO_EDGE, 2, 0, NO_EDGE, 5, NO_EDGE}); graph.weights.push_back(vector<DATA_TYPE>{NO_EDGE, NO_EDGE, NO_EDGE, NO_EDGE, 0, NO_EDGE, 6}); graph.weights.push_back(vector<DATA_TYPE>{NO_EDGE, NO_EDGE, NO_EDGE, NO_EDGE, 1, 0, 8}); graph.weights.push_back(vector<DATA_TYPE>{NO_EDGE, NO_EDGE, NO_EDGE, NO_EDGE, NO_EDGE, NO_EDGE, 0}); vector<DATA_TYPE> distance = dijkstra(graph.weights, 1); return 0; }

測試用例圖如下:

這裡寫圖片描述

編譯環境(CLion 2016 with MinGW G++, GDB 7.11)

輸出結果:
From 1 to 2|| Distance: 1 || Path: 1->2
FFrom 1 to 4|| Distance: 6 || Path: 1->2->5->4
From 1 to 5|| Distance: 5 || Path: 1->2->5
From 1 to 6|| Distance: 12 || Path: 1->2->5->4->6