單源最短路徑—Dijkstra演算法(C++)
阿新 • • 發佈:2019-02-10
最近複習圖演算法,練練手
先拿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