最短路徑簡單實現(Dijkastra算法和Floyd算法)

什麼是最短路徑:

圖中的某一個節點到另外某一個節點的最短路徑的權值和,如果是無權值的圖,則理解爲權值爲1的圖。

圖的鄰接矩陣結構:

要計算最短路徑,首先需要一個圖,這裏用鄰接矩陣來表示一個圖。

typedef char VertexType;        //頂點類型 ,默認爲char
typedef int EdgeType;              //邊的權值  默認int
#define MAXVERTEX 10          //最大的頂點數    默認爲10
#define INFINITY 65535              //表示無盡∞
								   //鄰接矩陣的結構
struct MGraph
{
	VertexType vexs[MAXVERTEX];     //頂點數組
	EdgeType arc[MAXVERTEX][MAXVERTEX];    //鄰接矩陣  即邊數組
	int vertexNum;            //頂點數
	int edgeNum;                 //邊數
};

Dijkastra算法:

Dijkastra算法把一個問題分解成小問題的集合,比如要計算V0~V9的最短路徑,先計算V0~V1的最短路徑,然後到V2,最終計算到V9的最短路徑。

typedef int ShortPathWeight[MAXVERTEX];      //存儲到各個頂點最短路徑的權值
typedef int PathPercursor[MAXVERTEX];     //存儲某個頂點最短路徑的前驅頂點,如PathPercursor[v8]=7,則到v8的最短路徑前一個是v7點

//Dijkastra算法最短路徑
void DijkastraShortestPath(MGraph G, int v0, ShortPathWeight *S, PathPercursor *P)
{
	int i, j;  //用於循環
	int min;   //用於記錄最短權值來比較
	int k;     //用於記錄最小權值頂點下標
	int OverVertex[MAXVERTEX];     //用於記錄已經求出最短路徑的頂點,當數組值爲0表示未求出,當數組值爲1表示已經求出
	//初始化要使用的數組
	for (i = 0; i < G.vertexNum; i++)
	{
		OverVertex[i] = 0;     //默認沒有求出任何點
		(*S)[i] = G.arc[0][i]; //把鄰接矩陣的第一行數據記錄到ShortPath數組
		(*P)[i] = 0;           //路徑數組初始化爲0
	}
	OverVertex[v0] = 1;          //源點V0不需要求,默認1
	(*S)[v0] = 0;              //V0到自身V0距離爲0
	//循環遍歷每一個頂點,來求出V0到每一個頂點vi的最短路徑
	for (i = 1; i < G.vertexNum; i++)        //i從1開始遍歷
	{
		//找出ShortPathWeight的最小值
		min = INFINITY;           //默認最小權值爲不可能數
		for (j = 0; j < G.vertexNum; j++)
		{
			if (OverVertex[j] != 1 && (*S)[j] < min)   //找出到頂點的最小值
			{
				k = j;
				min = (*S)[j];      //k頂點離源點最近,最小權值爲min
			}
		}
		OverVertex[k] = 1;           //把k頂點的標識符設爲true
		//在已經找到k頂點爲最短路徑的基礎上,循環尋找與K頂點連接的後面頂點的最短路徑
		for (j = 0; j < G.vertexNum; j++)
		{
			//經過K頂點到某一頂點的路徑比v0直接到某一頂點的路徑短
			if (OverVertex[j] != 1 && (min + G.arc[k][j]) < (*S)[j])
			{
				(*S)[j] = min + G.arc[k][j];
				(*P)[j] = k;
			}
		}
	}
}
用了兩個數組分別記錄到某點的最短路徑權值和前驅頂點,另外內部用一個標識符來表示是否已經求出某點的最短路徑。

Floyd算法:

Floyd非常巧妙,它設定了一箇中間頂點,比如要計算V0~V2的權值,中間頂點爲V1:比較(V0~V2)和(V0~V1+V1~V2)的值,把較小的值記錄爲最短權值。

typedef int ShortPathWeightMatrix[MAXVERTEX][MAXVERTEX];      //任意頂點到任意頂點最短路徑的權值矩陣
typedef int PathPercursorMatrix[MAXVERTEX][MAXVERTEX];       //任意頂點到任意頂點最短路徑的前驅頂點矩陣

//Floyd算法最短路徑
void FloydShortestPath(MGraph G, ShortPathWeightMatrix *S, PathPercursorMatrix *P)
{
	int i, j, k;  //用於循環
	//初始化數組
	for (i = 0; i < G.vertexNum; i++)
	{
		for (j = 0; j < G.vertexNum; j++)
		{
			(*S)[i][j] = G.arc[i][j];        //把S數組初始化爲G的鄰接矩陣
			(*P)[i][j] = j;                   //把P數組初始化爲0-VertexNum的矩陣,即最短路徑前驅爲自身
		}
	}
	//三重循環嵌套,k爲路徑中間經過點
	for (k = 0; k < G.vertexNum; k++)
	{
		for (i = 0; i < G.vertexNum; i++)
		{
			for (j = 0; j < G.vertexNum; j++)
			{
				//找到Vi到Vj的權值大於(Vi~Vk)+(Vk~Vj)的點
				if ((*S)[i][j] > (*S)[i][k] + (*S)[k][j])
				{
					//改變記錄的最短路徑權值
					(*S)[i][j] = (*S)[i][k] + (*S)[k][j];
					//把某點的最短路徑前驅頂點改爲K
					(*P)[i][j] = (*P)[i][k];
				}
			}
		}
	}
}

算法的時間複雜度:

Dijkastra算法用了兩重嵌套循環,所以時間複雜度爲O(n^2);

Floyd算法用了三重嵌套循環,所以時間複雜度爲O(N^3)。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章