宣告:圖片及內容基於:https://www.bilibili.com/video/BV16C4y1H7Zc?from=articleDetail
最短路徑
Dijkstra演算法
原理
資料結構
核心程式碼
findMinDist()
int MGraph::findMinDist(){
int length=INFINIT;
int number;
for(int i=0;i<vertexNum;i++){
if(s[i]==0){
if(length>dist[i]&&dist[i]!=0&&dist[i]!=INFINIT){
length=dist[i]; //注意記錄的是下標,我原來寫成length=dist[i]了,太慘了
number=i; //後來寫成length=i return i;大錯特錯
}
}
}
return number;
}
displayPath()
void MGraph::displayPath(){ //列印最短路徑
for(int i=0;i<vertexNum;i++){
if(i==startV) cout<<i<<endl; //起點直接列印
if(i!=startV){ //其他結點
int tmp=i;
stack<int> s; //逆序輸出使用棧
while(tmp!=startV){
s.push(path[tmp]);
tmp=path[tmp];
}
while(!s.empty()){
cout<<s.top()<<"->";
s.pop();
}
cout<<i;
cout<<endl;
}
}
}
Dijkstra(int startV)
void MGraph::Dijkstra(int startV){
this->startV=startV; //別忘了,startV也是MGraph的資料成員
for(int i=0;i<vertexNum;i++){
dist[i]=arc[startV][i]; //dist陣列初始化
if(dist[i]!=INFINIT) //path陣列初始化
path[i]=startV;
else
path[i]=-1;
}
for(int i=0;i<vertexNum;i++) //s陣列初始化
s[i]=0;
s[startV]=1; //startV放入集合
int num=1; //集合資料個數1
while(num<vertexNum){
int min=findMinDist(); //min是當前dist陣列中最短路徑的下標,前提是s[i]=0,即查詢的
//是集合的補集元素
s[min]=1; //min放入集合
for(int i=0;i<vertexNum;i++){ //更新dist和path陣列
if(s[i]==0&&(dist[i]>dist[min]+arc[min][i])){
dist[i]=dist[min]+arc[min][i];
path[i]=min;
}
}
num++;
}
displayPath(); //顯示全部最短路徑
}
完整程式碼
#include<iostream>
#define MAX 50
#define INFINIT 65535
#include <stack>
using namespace std;
class MGraph{
private:
int vertexNum,arcNum; //頂點數,邊數
int arc[MAX][MAX]; //鄰接矩陣
int vertex[MAX]; //頂點資訊
int dist[MAX]; //記錄單源到每個點的最短路徑的長度
int path[MAX]; //記錄當前從某點到某點的最短路徑,存放的是某點起點的頂點資訊
int s[MAX]; //記錄已經確定的最短路徑的結點集合
int startV;
public:
MGraph(int v[],int n,int e);
void display();
void Dijkstra(int startV);
int findMinDist();
void displayPath();
void displayDistPathS();
};
void MGraph::displayDistPathS(){
cout<<"dist:"<<endl;
for(int i=0;i<vertexNum;i++){
cout<<dist[i]<<" ";
}
cout<<endl;
cout<<"path:"<<endl;
for(int i=0;i<vertexNum;i++){
cout<<path[i]<<" ";
}
cout<<endl;
cout<<"S:"<<endl;
for(int i=0;i<vertexNum;i++){
cout<<s[i]<<" ";
}
cout<<endl;
}
MGraph::MGraph(int v[],int n,int e){ //n是頂點數,e是邊數
vertexNum=n;
arcNum=e;
for(int i=0;i<vertexNum;i++){
vertex[i]=v[i];
}
for(int i=0;i<arcNum;i++){ //初始化鄰接矩陣
for(int j=0;j<arcNum;j++){
if(i==j) arc[i][j]=0;
else arc[i][j]=INFINIT;
}
}
int vi,vj,w;
for(int i=0;i<arcNum;i++){
cout<<"請輸入有向邊的兩個頂點和這條邊的權值"<<endl;
cin>>vi>>vj>>w; //輸入邊依附的兩個頂點的編號 和權值
arc[vi][vj]=w; //有邊標誌
}
}
void MGraph::display(){
cout<<"鄰接矩陣:"<<endl;
for(int i=0;i<vertexNum;i++){
for(int j=0;j<vertexNum;j++){
if(arc[i][j]==INFINIT)
cout<<"∞"<<"\t";
else cout<<arc[i][j]<<"\t";
}
cout<<endl;
}
cout<<endl;
cout<<"結點資訊:"<<endl;
for(int i=0;i<vertexNum;i++){
cout<<vertex[i]<<" ";
}
cout<<endl;
}
int MGraph::findMinDist(){
int length=INFINIT;
int number;
for(int i=0;i<vertexNum;i++){
if(s[i]==0){
if(length>dist[i]&&dist[i]!=0&&dist[i]!=INFINIT){
length=dist[i]; //注意記錄的是下標,我原來寫成length=dist[i]了,太慘了
number=i; //後來寫成length=i return i;大錯特錯
}
}
}
return number;
}
void MGraph::displayPath(){ //列印最短路徑
for(int i=0;i<vertexNum;i++){
if(i==startV) cout<<i<<endl; //起點直接列印
if(i!=startV){ //其他結點
int tmp=i;
stack<int> s; //逆序輸出使用棧
while(tmp!=startV){
s.push(path[tmp]);
tmp=path[tmp];
}
while(!s.empty()){
cout<<s.top()<<"->";
s.pop();
}
cout<<i;
cout<<endl;
}
}
}
void MGraph::Dijkstra(int startV){
this->startV=startV; //別忘了,startV也是MGraph的資料成員
for(int i=0;i<vertexNum;i++){
dist[i]=arc[startV][i]; //dist陣列初始化
if(dist[i]!=INFINIT) //path陣列初始化
path[i]=startV;
else
path[i]=-1;
}
for(int i=0;i<vertexNum;i++) //s陣列初始化
s[i]=0;
s[startV]=1; //startV放入集合
int num=1; //集合資料個數1
while(num<vertexNum){
int min=findMinDist(); //min是當前dist陣列中最短路徑的下標,前提是s[i]=0,即查詢的
//是集合的補集元素
s[min]=1; //min放入集合
for(int i=0;i<vertexNum;i++){ //更新dist和path陣列
if(s[i]==0&&(dist[i]>dist[min]+arc[min][i])){
dist[i]=dist[min]+arc[min][i];
path[i]=min;
}
}
num++;
}
displayPath(); //顯示全部最短路徑
}
int main(){
int n,e;
int v[MAX];
cout<<"請輸入頂點數和邊數"<<endl;
cin>>n>>e;
cout<<"請輸入頂點資訊"<<endl;
for(int i=0;i<n;i++){
cin>>v[i];
}
cout<<"請輸入起點:"<<endl;
int t;
cin>>t;
MGraph mgraph(v,n,e);
mgraph.display();
mgraph.Dijkstra(t);
mgraph.displayDistPathS();
return 0;
}
輸入:
7 12
0 1 2 3 4 5 6
0
0 1 4
0 2 6
0 3 6
1 2 1
1 4 7
2 4 6
2 5 4
3 2 2
3 5 5
4 6 6
5 4 1
5 6 8
輸出:
鄰接矩陣:
0 4 6 6 ∞ ∞ ∞
∞ 0 1 ∞ 7 ∞ ∞
∞ ∞ 0 ∞ 6 4 ∞
∞ ∞ 2 0 ∞ 5 ∞
∞ ∞ ∞ ∞ 0 ∞ 6
∞ ∞ ∞ ∞ 1 0 8
∞ ∞ ∞ ∞ ∞ ∞ 0
結點資訊:
0 1 2 3 4 5 6
0
0->1
0->1->2
0->3
0->1->2->5->4
0->1->2->5
0->1->2->5->4->6
dist:
0 4 5 6 10 9 16
path:
0 0 1 0 5 2 4
S:
1 1 1 1 1 1 1