Dijkstra算法詳解:https://blog.csdn.net/longshengguoji/article/details/10756003
在解決單源點(diǎn)最短路徑的問題時(shí)掖蛤,常常用到經(jīng)典的Dijkstra算法旗笔,其算法的本質(zhì)思想是:按路徑長度遞增依次產(chǎn)生最短路徑惶桐。
下面給出算法的大致流程:
1.初始化所有結(jié)點(diǎn)并將起始點(diǎn)設(shè)為標(biāo)記贿衍,進(jìn)入以下循環(huán)
2.在到達(dá)某點(diǎn)的最短路徑中找最小且未標(biāo)記的點(diǎn)(可以用一維數(shù)組表示)
??如:
數(shù)組下標(biāo):0 ?1 ? 2 ? 3 ? 4 ? 5
? ?Len ? ? ?:- ? 0 ? 5 ?10 ?2 ? -
這個(gè)數(shù)組表示 1號(hào)節(jié)點(diǎn)為初始節(jié)點(diǎn)救恨,1號(hào)節(jié)點(diǎn)到達(dá)2號(hào)節(jié)點(diǎn)的最短路徑為5贸辈,到3號(hào)為10肠槽,無法到達(dá)5號(hào)(具體可以以較大的數(shù)表示其路徑)奢啥。
從中找到一個(gè)未標(biāo)記且Len最短的一個(gè)嘴拢,未標(biāo)記用另一數(shù)組記錄
如:
數(shù)組下標(biāo):0 ? 1 ? 2 ? 3 ? 4 ? 5
? ?標(biāo)記 ? ? :0 ? 1 ? 0 ? 0 ? 1 ? 0
此數(shù)組表示從初始節(jié)點(diǎn)到達(dá)4號(hào)節(jié)點(diǎn)的最短路徑已找到
從以上兩個(gè)數(shù)組中可以得出:此次循環(huán)找到的點(diǎn)為2號(hào)節(jié)點(diǎn),進(jìn)入下一步
3.標(biāo)記找到的點(diǎn)席吴,以此標(biāo)記點(diǎn)為中間點(diǎn)重新計(jì)算所有未標(biāo)記點(diǎn)的最短路徑(更新最短路徑表)
4.循環(huán)1.2步至n-1次(n為頂點(diǎn)數(shù),若最后還有未被標(biāo)記的孝冒,說明無法到達(dá)此點(diǎn))
下面是核心代碼:
[cpp]?view plain?copy
while(count
??????{??
??????????tempmin=INFINITE;??
for(i=1;i<=n;i++)??
??????????{??
if(in[i]==0&&Len[i]
??????????????{??
??????????????????tempmin=Len[i];??
??????????????????si=i;??
??????????????}??
??????????}??
??????????in[si]=1;??
??????????count++;??
for(i=1;i<=n;i++)?//updata?the?length??
??????????{??
if(in[i]==0&&(tempmin+mGraph.matrix[si][i])
??????????????{??
??????????????????Len[i]=tempmin+mGraph.matrix[si][i];??
??????????????}??
??????????}??????
??????}??
核心部分是上面的兩個(gè)for循環(huán),第一個(gè)for循環(huán)遍歷所有結(jié)點(diǎn)伤靠,找到未標(biāo)記并且長度最短的路徑啼染;第二個(gè)for循環(huán)也是遍歷所有結(jié)點(diǎn)以上面找到的最短路徑結(jié)點(diǎn)為中間點(diǎn)更新最短路徑表宴合;注意在第一個(gè)for循環(huán)之后要標(biāo)記找到的點(diǎn)(說明到達(dá)此點(diǎn)的最短路徑已找到)
下面用一個(gè)實(shí)例來具體說明:
若有這樣一張有向圖(此圖為《數(shù)據(jù)結(jié)構(gòu)》嚴(yán)蔚敏 p188頁迹鹅,書中沒有詳細(xì)講解,現(xiàn)以此為實(shí)例)
V0-V5 共6個(gè)節(jié)點(diǎn)斜棚,節(jié)點(diǎn)間路徑已標(biāo)出,現(xiàn)要求從V0到其余各節(jié)點(diǎn)的最短路徑蚤霞;
有上面的算法流程可知,在使用Dijkstra算法時(shí)需要幾個(gè)結(jié)構(gòu)來保存我們想要的信息:
1.保存這張圖的結(jié)構(gòu)體
2.記錄V0到其余各節(jié)點(diǎn)最短路徑的數(shù)組(這里設(shè)為Len[n+1])
3.記錄某節(jié)點(diǎn)是否已找到最短路徑的數(shù)組(這里設(shè)為in[n+1])
接下來就是算法實(shí)現(xiàn)部分:
1.標(biāo)記V0 -- in[1]=1 ? 初始化 Len[]={INFINITE , 0 , INFINITE , 10, INFINITE , 30 , 100} ?這里數(shù)組首元素未用到昧绣,數(shù)組下標(biāo)從1開始表示V0以此類推
2.第一次循環(huán)與V0相鄰的有V2捶闸、V4夜畴、V5删壮,其中V2距離最短為10,標(biāo)記V2央碟,并且以V2為中間點(diǎn)(路徑為V0->V2->Vx)更新最短路表,此時(shí)V3被更新為10+50=60,。
3.進(jìn)入第二次循環(huán),此時(shí)未被標(biāo)記的有V1边酒、V3狸窘、V4墩朦、V5,翻擒,其中從V0到這些的臨時(shí)最短路分別為INFINITE、60陋气、30、100巩趁,從中找到最小的即V4,將V4標(biāo)記為1议慰,以V4為中間點(diǎn)(路徑為V0->V4->Vx)更新最短路表,此時(shí)V3被更新為50草讶,V5被更新為90。
4.進(jìn)入第三次循環(huán)堕战,此時(shí)未被標(biāo)記的有V1拍霜、V3嘱丢、V5祠饺,其中臨時(shí)最短路分別為INFINITE、50吠裆、90烂完,從中找到最小的即V3,將V3標(biāo)記為1抠蚣,以V3為中間點(diǎn)(路徑為V0->V4->V3->Vx)更新最短路表,此時(shí)V5被更新成60。
5.進(jìn)入第四次循環(huán)距贷,此時(shí)未被標(biāo)記的有V1、V5忠蝗,其中臨時(shí)最短路分別為INFINITE、60阁最,找到V5骇两,標(biāo)記為1速种,以V5為中間點(diǎn)更新最短路表低千,此時(shí)沒有元素被更新
6.進(jìn)入第五次循環(huán),這次循環(huán)沒找到任何東西
7.退出循環(huán)示血,Len表中即為V0到其余各個(gè)節(jié)點(diǎn)的最短路徑。
以上就是Dijkstra算法最基本的思想矾芙,當(dāng)然,在找最短路時(shí)我們常常會(huì)需要求出到達(dá)某點(diǎn)的最短路徑拂铡,那么下面,我們就來看看要怎樣記錄下到達(dá)某點(diǎn)的最短路徑:
在Dijkstra算法的前提下加入查詢最短路徑其實(shí)很簡單感帅,只要在每次更新最短路時(shí)保存在該頂點(diǎn)的父節(jié)點(diǎn)序號(hào)即可地淀,最后輸出時(shí)回退中間節(jié)點(diǎn)然后用堆棧輸出即可
最后直接給出完整代碼(寫的很一般失球,還望指教):
[cpp]?view plain?copy
#include???
#include???
#define?MAX_LEN?100??
#define?INFINITE?1000??
typedef?struct?graph??
{??
int?nodenum;??
int?edgenum;??
int?matrix[MAX_LEN][MAX_LEN];??
}Graph;??
typedef?struct?stack??
{??
int??bottom;??
int??top;??
int??printout[MAX_LEN];??
}mstack;??
int?in[MAX_LEN];??
int?Len[MAX_LEN];??
int?path[MAX_LEN];??
void?InitStack(mstack?*s)??
{??
????s->bottom=0;??
????s->top=0;??
memset(s->printout,0,sizeof(int)*MAX_LEN);??
}??
void?push(mstack?*s,int?m)??
{??
????s->printout[s->top++]=m;??
}??
int?pop(mstack?*s)??
{??
return?s->printout[--s->top];??
}??
void?InitGraph(Graph?*g,int?n)??
{??
int?i,j;??
for(i=1;i<=n;i++)??
for(j=1;j<=n;j++)??
??????????{??
if(i==j)g->matrix[i][j]=0;??
else?g->matrix[i][j]=INFINITE;???????
??????????}??
for(i=1;i<=n;i++)??
?????{??
?????????in[i]=0;??
?????????Len[i]=INFINITE;??
?????????path[i]=0;??
?????}??
}??
int?main()??
{??
int?n,m,i,A,B,templen,count,min,tempmin,si,temp;??
while(scanf("%d?%d",&n,&m))??
????{??
????????count=0;??
????????Graph?mGraph;??
????????mGraph.edgenum=m;??
????????mGraph.nodenum=n;??
????????InitGraph(&mGraph,n);??
for(i=0;i
????????{??
scanf("%d?%d?%d",&A,&B,&templen);??
????????????mGraph.matrix[A][B]=templen;??
????????}??
????????in[1]=1;??
path[1]=1;//sava?path??
????????Len[1]=0;??
for(i=2;i<=n;i++)??
????????{??
Len[i]=mGraph.matrix[1][i];//Init?the?len??
if(Len[i]!=INFINITE)path[i]=1;??
????????}??
????????min=0;??
????????si=1;??
while(count
????????{??
????????????tempmin=INFINITE;??
for(i=1;i<=n;i++)??
????????????{??
if(in[i]==0&&Len[i]
????????????????{??
????????????????????tempmin=Len[i];??
????????????????????si=i;??
????????????????}??
????????????}??
????????????in[si]=1;??
for(i=1;i<=n;i++)?//updata?the?length??
????????????{??
if(in[i]==0&&(tempmin+mGraph.matrix[si][i])
????????????????{??
????????????????????Len[i]=tempmin+mGraph.matrix[si][i];??
????????????????????path[i]=si;??
????????????????}??
????????????}??
????????????count++;???
????????}??
????????mstack?s;??
for(i=1;i<=n;i++)??
????????{??
????????????temp=i;??
????????????InitStack(&s);??
if(path[temp]==0)??
????????????{???
printf("no?path\n");??
continue;??
????????????}??
while(path[temp]!=1)??
????????????{??
????????????????push(&s,path[temp]);??
????????????????temp=path[temp];??
????????????}??
printf("1-->");??
while(s.bottom!=s.top)??
????????????{??
printf("%d-->",pop(&s));??
????????????}??
printf("%d??min?length?is?%d\n",i,Len[i]);??
????????}??
????}??
return?0;??
}??
附上上面那張圖的結(jié)果(V0節(jié)點(diǎn)為1实苞,V1節(jié)點(diǎn)為2.烈疚。黔牵。爷肝。以此類推)