Dijkstra算法
定義概覽
Dijkstra(迪杰斯特拉)算法是典型的單源最短路徑算法,用于計算一個節點到其他所有節點的最短路徑。主要特點是以起始點為中心向外層層擴展,直到擴展到終點為止。Dijkstra算法是很有代表性的最短路徑算法,在很多專業課程中都作為基本內容有詳細的介紹,如數據結構,圖論,運籌學等等。注意該算法要求圖中不存在負權邊。
問題描述:在無向圖 G=(V,E) 中,假設每條邊 E[i] 的長度為 w[i],找到由頂點 V0 到其余各點的最短路徑。(單源最短路徑)算法描述
- 算法思想:設G=(V,E)是一個帶權有向圖,把圖中頂點集合V分成兩組,第一組為已求出最短路徑的頂點集合(用S表示,初始時S中只有一個源點,以后每求得一條最短路徑 , 就將加入到集合S中,直到全部頂點都加入到S中,算法就結束了),第二組為其余未確定最短路徑的頂點集合(用U表示),按最短路徑長度的遞增次序依次把第二組的頂點加入S中。在加入的過程中,總保持從源點v到S中各頂點的最短路徑長度不大于從源點v到U中任何頂點的最短路徑長度。此外,每個頂點對應一個距離,S中的頂點的距離就是從v到此頂點的最短路徑長度,U中的頂點的距離,是從v到此頂點只包括S中的頂點為中間頂點的當前最短路徑長度。
- 算法步驟:
a.初始時,S只包含源點,即S={v},v的距離為0。U包含除v外的其他頂點,即:U={其余頂點},若v與U中頂點u有邊,則<u,v>正常有權值,若u不是v的出邊鄰接點,則<u,v>權值為∞。
b.從U中選取一個距離v最小的頂點k,把k,加入S中(該選定的距離就是v到k的最短路徑長度)。
c.以k為新考慮的中間點,修改U中各頂點的距離;若從源點v到頂點u的距離(經過頂點k)比原來距離(不經過頂點k)短,則修改頂點u的距離值,修改后的距離值的頂點k的距離加上邊上的權。
d.重復步驟b和c直到所有頂點都包含在S中。
/*** 遞歸
**graph:存儲圖信息的內存地址,圖已排好序
**dist:圖中每個點到S點的距離,初始都為0
**v[]:圖中每個點是否訪問過的標志
**vn:當前訪問的節點ID
**uNum:圖中剩余沒訪問點數,為0則程序結束。
***/
void dijkstra(graph_t *graph, int dist[], int v[], int vn, int uNum)
{
if(uNum <= 0){
return;
}
printf("%d--%d\n",vn, uNum);
int flag = 1, vt = 0;
gnode_t *p = graph->relation[vn].next; /* 與VN相連接的點 */
if(p == NULL){
return ;
}
v[vn] = 1;
while(p != NULL){ /* 訪問所有與VN相連接的點 */
if(flag && !v[p->data]){ /* 與vn相連的未被訪問過的最近(越靠前越近)的點,用作往下遞歸的起點 */
vt = p->data;
flag = 0;
}
if(0 == dist[p->data] || dist[p->data] > dist[vn] + p->weight){ /* 無向圖,p->weight為權重 */
dist[p->data] = dist[vn] + p->weight;
}
printf(" %d -- %d\n",p->data, dist[p->data]);
p = p->next;
}
dijkstra(graph, dist, v, vt, --uNum);
}