[C++]單源最短路徑:迪傑斯特拉(Dijkstra)算法(貪心算法)


1 Dijkstra算法

1.1 算法基本信息

  • 解決問題/提出背景

    • 單源最短路徑(在帶權有向圖中,求從某頂點到其余各頂點的最短路徑)
  • 算法思想

    • 貪心算法
      • 按路徑長度遞增的次序,依次產生最短路徑的算法
    • 【適用范圍】Dijkstra算法僅適用於【權重為正】的圖模型中
  • 時間復雜度

    • O(n^3)
  • 補充說明

    • 亦可應用於【多源最短路徑】(推薦:Floyd算法(動態規划,O(n^3)))
      • Dijkstra 時間復雜度:O(n^3)

1.2 算法描述

  • 1.2.1 求解過程(具體思路)
  • 1.2.2 示例

1.2 編程復現

  • 1> 定義圖模型(鄰接矩陣表示法)的【基本存儲結構體】
# define MaxInt 32767 // 表示極大值 即 ∞ (無窮大)
# define MVNum 100 // 最大頂點數 

typedef int VertexType; // 假設頂點的數據類型為整型

typedef int ArcType; // 假設Vi與Vj之邊的權值類型為整型 

typedef struct {
 	VertexType vexs[MVNum]; // 頂點表 (存儲頂點信息)
	ArcType arcs[MVNum][MVNum]; // 鄰接矩陣
	int vexnum,arcnum; // 圖的當前頂點數與邊數 
}AMGraph; // Adjacent Matrix Graph 鄰接矩陣圖 
  • 2> 定義 Dijkstra 算法的【輔助數據結構體】
bool S[MVNum]; // S[i] 記錄從源點V0到終點Vi是否已被確定為最短路徑長度  【划分確定與未確定: 跟貪心算法的適用范圍(不可取消性)有直接聯系】
			   // true:表已確定;false:表尚未確定
ArcType D[MVNum]; // D[i] 記錄從源點V0到終點Vi的【當前】最短路徑【長度】 
int Path[MVNum];  // Path[i] 記錄從源點V0到終點Vi的【當前】最短路徑上【Vi的[直接前驅]的頂點序號】 
  • 3> 初始化(鄰接矩陣)帶權有向圖的圖模型
void InitAMGraph(AMGraph &G){
	cout<<"Please Input Vertexs Number:";
	cin>>G.vexnum;
	cout<<"\nPlease Directed Edges Number:";
	cin>>G.arcnum;
	
	for(int i=0;i<MVNum;i++){
		for(int j=0;j<MVNum;j++){
			if(i!=j){ // 【易錯】 初始化<Vi, Vj>時: <Vi,Vj> 路徑長度無窮大 (i!=j) 
				G.arcs[i][j] = MaxInt;
			} else { //  【易錯】 初始化<Vi, Vj>時: <Vi,Vi>【自回環】路徑長度為0 (i==i) 
				G.arcs[i][j] = 0;
			}
		}
	}
	for(int i=0;i<G.vexnum;i++){
		G.vexs[i] = i;
	}
	cout<<"\nPlease Input All Directed Edges and their Weight now:";
	cout<<"\nDirected Edges(i,j,weight): "<<endl;
	int i,j;
	int weight;
	for(int k=0;k<G.arcnum;k++){
//		cout<<"("<<(k+1)<<") ";
		cin>>i;cin>>j;cin>>weight;
		G.arcs[i][j] = weight;
	}
	cout<<endl;
}
  • 4> Dijkstra算法:求解單源最短路徑
void ShortestPath_Dijkstra(AMGraph G, int V0){
	//step1 n個頂點依次初始化
	int n =G.vexnum;  
	for(int v=0;v<n;v++){
		S[v] = false;
		D[v] = G.arcs[V0][v];
		if(D[v]<MaxInt){
			Path[v] = V0;
		} else {
			Path[v] = -1;
		}
	}
	//step2 將源點V0划入已確定集合S中 
	S[V0] = true;
	D[V0] = 0; // 源點V0到源點V0的最短路徑長度必然為0
	//step3 貪心算法策略:
	//			3.1 循環遍歷所有結點:
	//				3.2 先確定當前最短路徑的終點v;
	//				3.3 然后,將v划入已確定集合S中;
	//				3.4 最后,以利用結點v更新所有尚未確定的結點的最短路徑
	int v;
	int min;
	D[G.vexnum] = MaxInt;
	for(int i=1;i<n;i++){//3.1循環遍歷所有結點 (即 求從源點V0到圖中每一頂點(共計n-1個頂點)的最短路徑) 
		//3.2 確定當前最短路徑的終點v;
		min = MaxInt;
		for(int w=0;w<n;w++){
			if(S[w]==false && D[w]<min){//比本輪循環中,已知的最短路徑還短 【易錯/易漏】 S[w]==false : 必須滿足當前結點 Vw 屬於尚未確定的結點 
				v = w;
				min = D[w];
			}
		}
		//3.3 然后,將v划入已確定集合S中;
		S[v] = true;
		//3.4 最后,以利用結點v更新所有尚未確定的結點的最短路徑
		for(int w=0;w<n;w++){
			//↓更新Vw結點的最短路徑長度為 D[v] + G.arcs[v][w] 
			//cout<<"S["<<w<<"]:"<<S[w]<<"D["<<v<<"]"<<D[v]<<"G.arcs["<<v<<"]["<<w<<"]"<<"D["<<w<<"]"<<D[w]<<endl; 
			if(S[w]==false && (D[v] + G.arcs[v][w] < D[w])){//【易錯/易漏】 S[w]==false : 必須滿足當前結點 Vw 屬於尚未確定的結點 
				D[w] = D[v] + G.arcs[v][w];
				Path[w] = v; // 更新 結點Vw的前驅為 v 
			}
		}
		v = G.vexnum;
	} 
}
  • 5> 輸出結果 D[i]、Path[j]
void OutputD(AMGraph G, int V0){
	cout<<"Shortest Distance Weight of the Pair of Directed Vertices("<<V0<<", j):"<<endl; 
	for(int j=0;j<G.vexnum;j++){
		cout<<D[j]<<"\t"; 
	}
	cout<<endl;
}

void OutputPath(AMGraph G,int V0){
	cout<<"Shortest Distance Path("<<V0<<",j) of the Pair of Directed Vertices:"<<endl; 
	for(int j=0;j<G.vexnum;j++){
		cout<<Path[j]<<"\t"; 
	}
	cout<<endl;
}
  • 6> 執行:Main函數
int main(){
	int V0; //源點V0的下標 
	AMGraph G;
	InitAMGraph(G);
	
	cout<<"Please Input the Index of Source Node 'V0':";
	cin>>V0;
	ShortestPath_Dijkstra(G, V0);
	OutputD(G, V0);
	OutputPath(G, V0);
	return 0;
}
  • 7> Test: Output of Main
Please Input Vertexs Number:6

Please Directed Edges Number:8

Please Input All Directed Edges and their Weight now:
Directed Edges(i,j,weight):
1 2 5
0 2 10
3 5 10
4 3 20
0 4 30
2 3 50
4 5 60
0 5 100

Please Input the Index of Source Node 'V0':0

Shortest Distance Weight of the Pair of Directed Vertices(0, j):
0       32767   10      50      30      60

Shortest Distance Path(0,j) of the Pair of Directed Vertices:
0       -1      0       4       0       3

2 參考文獻

  • 《數據結構(C語言版/ 嚴蔚敏 李冬梅 吳偉民 編)》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM