1. 程式人生 > >最短路徑之Dijkstra演算法

最短路徑之Dijkstra演算法

Dijkstra(迪傑斯特拉)演算法是典型的最短路徑路由演算法,用於計算一個節點到其他所有節點的最短路徑。主要特點是以起始點為中心向外層層擴充套件,直到擴充套件到終點為止(BFS、prime演算法都有類似思想)。Dijkstra演算法能得出最短路徑的最優解,但由於它遍歷計算的節點很多,所以效率低。

1、演算法思想

令G = (V,E)為一個帶權有向網,把圖中的頂點集合V分成兩組:已求出最短路徑的頂點集合S(初始時S中只有源節點,以後每求得一條最短路徑,就將它對應的頂點加入到集合S中,直到全部頂點都加入到S中);未確定最短路徑的頂點集合V-S。在加入過程中,總保持從源節點v到S中各頂點的最短路徑長度不大於從源節點v到V-S中任何頂點的最短路徑長度。

2、演算法描述

(1)S為已經找到的從v出發的最短路徑的終點集合,它的初始狀態為空集,那麼從v出發到圖中其餘各頂點(終點)vi(vi∈V-S)可能達到的最短路徑長度的初值為:

         d[i] = arcs[LocateVex(G, v)][i],vi∈V

(2)選擇vj,使得 d[j] = Min{d[i]|vi屬於V-S},vj就是當前求得的一條從v出發的最短路徑的終點。令S=S∪{j};

(3)修改從v出發到集合V-S上任一頂點vk可達的最短路徑長度。如果 d[j] + arcs[j][k] < d[k], 則修改d[k]為:d[k] = d[j] + arcs[j][k];

(4)重複(2),知道所有頂點都包含在S中,此時得到v到圖上其餘各頂點的最短路徑是依路徑長度遞增的序列。

具體圖例與演算法執行步驟:(從A開始,到各節點的最短路徑)


具體執行步驟如下圖所示:


PS:圖片右下角是原作者的部落格地址。

3、演算法具體實現

typedef int PathMatrix;            //用於儲存最短路徑序列的頂點下標陣列
typedef EdgeType ShortPathTable;  //用於儲存到各點最短路徑的權值和
/* Dijkstra演算法求有向網g的下標為v0的頂點到其餘頂點下標為v的最短路徑P[v]及帶權長度D[v] */ 
/* P[v]的值為前驅頂點下標,D[v]表示v0到v的最短路徑長度和 */ 
void ShortestPath_DIJ(Graph *g, int v0, PathMatrix p[], ShortPathTable d[])
{
	int i, v, w, k;
	EdgeType min;
	bool final[MAX_VEX];	/* final[w]=1表示求得頂點V0至Vw的最短路徑 */

	//初始化資料
	for (v = 0; v < g->vexNum; v++)
	{
		final[v] = false;	   //全部頂點初始化為未知最短路徑狀態
		d[v] = g->arc[v0][v];  //將與v0點有連線的頂點加上權值
		p[v] = v0;			   //初始化路徑陣列P為v0
	}
	d[v0] = 0;				  //v0至v0的路徑為0
	final[v0] = true;		  //v0∈S, v0至v0不需要求路徑

	//開始主迴圈,每次求得v0到某個v頂點的最短路徑,並 加入v到集合S
	for (i = 0; i < g->vexNum; i++)
	{
		if (i == v0) continue;
		min = INFINITY;
		for (w = 0; w < g->vexNum; w++)	 //尋找V-S中離v0最近的頂點
		{
			if (!final[w] && d[w] < min)
			{
				min = d[w];	   //下標為w的頂點離v0更近
				v = w;
			}
		}
                //if (v == t) break;    //如果只查詢到下標為t的某個頂點
		final[v] = true;	//下標為k的頂點併入集合S,即將當前找到了最短路徑的頂點標記為true

		//更新當前最短路徑及距離
		for (w = 0; w < g->vexNum; w++)
		{
			//如果經過v頂點的路徑比現在這條路徑的長度短的話
			if (!final[w] && (min + g->arc[v][w] < d[w]))
			{
				//說明找到了更短的路徑,修改D[w]和P[w]
				d[w] = min + g->arc[v][w];
				p[w] = v;
			}
		}
	}
}

 下面是根據路徑陣列PathMatrix得到具體的路徑序列:

// 查詢從源點v到終點u的路徑,並輸出
void SearchPath(VertexType vex[], PathMatrix *prev,int v, int u)
{
	int que[MAX_VEX];
	int tot = 0;
	que[tot++] = u;	 //終點u
	int tmp = prev[u];   //到頂點下標u的路徑上的上一個頂點下標
	while(tmp != v)
	{
		que[tot++] = tmp;
		tmp = prev[tmp];   //到頂點下標tmp的路徑上的上一個頂點下標
	}
	que[tot] = v;
	for(int i = tot; i >= 0; --i)
		if(i != 0)
			printf("%c -> ", vex[que[i]]);
		else
			printf("%c", vex[que[i]]);
}

以上面的無向網為例,執行結果截圖:


dijkstra演算法兩個應用題:

           資料結構(C語言版)

推薦幾篇搜尋演算法相關的非常好的博文: