1. 程式人生 > >dijkstra演算法求最短路徑

dijkstra演算法求最短路徑

希望大家能看完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.
最後看一下執行截圖
這裡寫圖片描述