dijkstra演算法求最短路徑
阿新 • • 發佈:2019-02-10
希望大家能看完prim演算法後再來看這個演算法,因為兩者思路差不多。
先來看一下自定義的結構體
typedef char VexType;
typedef int AdjType;
typedef struct{
int n;
VexType vexs[MaxNode];//儲存節點
AdjType arcs[MaxNode][MaxNode];//從矩陣獲得節點與節點間的距離
}GraphMatrix;
typedef struct{
AdjType length;//邊長
int prevex;//先驅節點
}path;
主程式
void main()
{
GraphMatrix *mygraph;
path *mydist;
// Edge *mymst;
mygraph = (GraphMatrix*)malloc(sizeof(GraphMatrix));
//mymst = (Edge*)malloc(sizeof(Edge));
mydist = (path*)malloc(sizeof(path));
CreateGraph(mygraph,6);
printf("testing creategraph\n");
dijkstra(mygraph,mydist);
printf("testing dijkstra:\n");
print_path(mygraph,mydist);
}
creategraph函式是從txt裡讀取矩陣的函式,我寫在了prim演算法的帖子裡,大家可以去看一下,這裡就不說了。
來看一下dikstra演算法
void dijkstra(GraphMatrix *graph,path *dist)
{
int i,j,min;
AdjType minw;
dist[0].length = 0;
dist[0].prevex = 0;
graph->arcs[0][0] = 1;//表示v0加入集合
for(i=1;i<graph->n;i++)//從V1節點開始
{
dist[i].length = graph->arcs[0][i];//初始化v0到各個節點的距離
if(dist[i].length!=Max)
{
dist[i].prevex = 0;//不等於Max說明V0可以到Vi節點
}
else
{
dist[i].prevex = -1;//V0到Vi沒有路徑
}
}
for(i=1;i<graph->n;i++)//一次迴圈就會找到V0到其中一個頂點的最短距離,所以迴圈節點數-1次
{
minw = Max;
min = 0;
for(j=1;j<graph->n;j++)
{
if((graph->arcs[j][j]==0)&&(dist[j].length<minw))//==0說明節點j還未加入
{
minw = dist[j].length;
min = j;
}
}
if(min==0)//如果都不等於0,說明所有節點都已加入,也就是已經調整好了,如果都大於minw說明所有路徑已經達到最短
{
break;
}
graph->arcs[min][min]=1;//將頂點為min的頂點加入集合,此時V0到Vmin的節點的最短距離已經找到,下面進行調整時就是判斷通過Vmin點再到其他點距離是否會減少
for(j=1;j<graph->n;j++)
{
if(graph->arcs[j][j]==1)
{
continue;//V0到節點Vi的最短路徑已經找到,不在進行調整
}
if(dist[j].length>dist[min].length+graph->arcs[min][j])//V0到Vmin的距離+Vmin到Vj的距離
{
dist[j].length = dist[min].length+graph->arcs[min][j];//變更路徑長度
dist[j].prevex = min;//V0到Vj的先驅節點從V0變更成Vmin
}
}
}
}
dist陣列的元素是V0節點到其他各點的路徑。如果二維陣列的graph->arcs[i][i]的值為0,說明此時Vi節點還沒加入我們的判斷範圍,就是說我們求得最短路徑裡不能經過Vi節點,所以我們一開始預設V0節點加入判斷範圍,也就是說,我們求得路徑就是V0節點到其他節點的最短路徑,所以for迴圈是從1開始的。以為不用求V0到V0的最短路徑
先初始化V0到其他各節點的距離,這些距離是從txt裡儲存的矩陣中讀取的。如果兩個節點之間沒有路徑,就預設路徑距離為1000.路徑前驅節點為-1.
1.初始化完成後,進行fo迴圈來尋找最短路徑。先找一條最短路徑(當前陣列元素裡length最小的).if((graph->arcs[j][j]==0)&&(dist[j].length
void print_path(GraphMatrix* graph, path* dist)
{
int i,j;
for(i=1;i<graph->n;i++)
{
j = i;
if(dist[i].length==Max)
{
printf("V0到V%d沒有路徑\n",i);//設定床為MAX說明沒有路徑
}
else
{
printf("V%d到V0的路徑為: %d ",i,i);
while(dist[j].prevex!=0)//Vj的前驅節點不是V0說明經過其他節點Vx,V0到Vx的路徑中的前驅節點為dist[j].prevex,迴圈驗證
{
printf("%d ",dist[j].prevex);
j = dist[j].prevex;
}
printf("0");
printf("\nV%d到V0的路徑長度為%d\n",i,dist[i].length);
printf("\n\n");
}
}
}
這裡其實就是把陣列元素的一些成員打印出來。陣列下標i就代表V0到Vi的最短路徑.
需要說明兩點.
1.上面已經提到了,如果路徑長度等於MAX(1000)。說明兩個節點之間沒有路徑。
2.我們找的最短路徑是V0到其他節點的最短路徑。如果第i條路徑的前驅節點不是V0,假設為Vj,說明V0到這個節點的最短路徑是經過其他節點的。這個時候我們還要找第J條路徑,就這樣往前找,知道前驅節點為V0.
最後看一下執行截圖