Dijkstra算法詳解

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.烈疚。黔牵。爷肝。以此類推)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末陆错,一起剝皮案震驚了整個(gè)濱河市金赦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌夹抗,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件兔朦,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡沽甥,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門亥曹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來恨诱,“玉大人媳瞪,你說我怎么就攤上這事照宝。” “怎么了厕鹃?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長剂碴。 經(jīng)常有香客問我,道長忆矛,這世上最難降的妖魔是什么察蹲? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任催训,我火速辦了婚禮,結(jié)果婚禮上漫拭,老公的妹妹穿的比我還像新娘。我一直安慰自己嫂侍,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布菲盾。 她就那樣靜靜地躺著,像睡著了一般懒鉴。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上临谱,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天奴璃,我揣著相機(jī)與錄音,去河邊找鬼苟穆。 笑死,一個(gè)胖子當(dāng)著我的面吹牛雳旅,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播攒盈,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼型豁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起偷遗,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎喉酌,沒想到半個(gè)月后泵喘,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體泪电,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡纪铺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了突诬。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片苫拍。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡旺隙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蔬捷,到底是詐尸還是另有隱情,我是刑警寧澤周拐,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站妥粟,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏罕容。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一露泊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧惭笑,春花似錦、人聲如沸沉噩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽长已。三九已至,卻和暖如春术瓮,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背胞四。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留辜伟,地道東北人脊另。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓甘苍,卻偏偏與公主長得像尝蠕,于是被迫代替她去往敵國和親载庭。 傳聞我的和親對(duì)象是個(gè)殘疾皇子廊佩,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容