最短路徑問題,BFS,408方向,思路與實現分析
繼上回挖下的坑,不知道大家有沒有認真看最小生成樹呢?很簡單,這回也講講正常難度的,看不懂就來這裡看看,講的很好~~
最短路徑問題
說起這個問題,先說個問題吧~~
這回不修路了,這回運東西哈哈哈,abcde五個城市,a是絲綢產業重地,那麼經常要往,bcde4個城市運東西,那麼到各個城市怎麼運送距離最近呢?圖示見下~~
a分別到各個城市運送,這是一個單源最短路徑問題~~
那麼如果各個城市之間都有特產,需要相互的兩兩之間運送距離最近呢?這就是各頂點之間的最短路徑問題~
所以明確一下,要搞的這三個演算法當然是有適用範圍的~~
單源最短路徑-BFS求無權圖思路
BFS其實也就是廣度優先遍歷,圖的廣度優先遍歷這裡我們來模擬一下~~
當然,無權圖你也可以想象成權值為一的特殊帶權圖嘛~~
第一次遍歷,我們訪問的元素應該是1和6~~
第二次遍歷,我們訪問的元素應該是5,3和7~~
第三次遍歷,我們訪問的元素應該是4和8~~
BFS程式碼實現與分析
先來程式碼~~
void BFS_MIN_Distance(Graph G,int u)
{
for(i = 0;i < G.vexnum; ++i)
{
d[i] = false; //單源到各點路徑長度的最短路徑,先初始化,false代表不可到達
path[i] = -1; //最短路徑從哪個頂點過來,先初始化
}
d[u] = 0;
visited[u] =TRUE; //標記頂點u已被標記
EnQueue(Q,u);//頂點u入佇列
while(!isEmpty(Q))//主過程
{
DeQueue(Q,u);//頂點u出佇列
for(w = FirstNeighbor(G,u); w >= 0; w = NextNeighbor(G,u,w))
{ //遍歷當前出佇列的元素的所有鄰接頂點,第一次為遍歷頂點u的所有鄰接頂點
//當前出佇列的元素即跳出for迴圈之後,再進入for迴圈時,本例中,u即為1號元素
if(!visited[w]) //w為u為尚未訪問的鄰接頂點
{
d[w] = d[u] +1;//路徑長度加1
path[w] = u; //最短路徑為u到w
visited[w] = TRUE;//標記頂點w已被標記
EnQueue(Q,w);//頂點w入佇列
}
}
}
}
我們需要列出3塊內容幫助我們分析~~
visited陣列:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
---|---|---|---|---|---|---|---|---|
visited | false | false | false | false | false | false | false | false |
隊:開始的時候沒有元素~~
d[]和path[]陣列
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
---|---|---|---|---|---|---|---|---|
d[] | false | false | false | false | false | false | false | false |
path[] | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
分析一下到while主過程之前,我們做的事情~~
visited陣列:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
---|---|---|---|---|---|---|---|---|
visited | false | true | false | false | false | false | false | false |
隊: 2 ,u為2
d[]和path[]陣列
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
---|---|---|---|---|---|---|---|---|
d[] | false | 0 | false | false | false | false | false | false |
path[] | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
那麼此時進入while迴圈~~
第一次while迴圈,2出隊~~
隊: 空,此時2出隊了~~
進入for迴圈~~
第一次for,u為2,第一個鄰接頂點為1,並且1尚未訪問,所以路徑長度加1,最短路徑為u到w,即2到1,標記1已訪問,1入隊,w=NextNeighbor,還有鄰接頂點,所以繼續~~
第二次for,第二個u的鄰接頂點,為6,並且6尚未訪問所以路徑長度加1,最短路徑為u到w,即2到6,標記6已訪問,6入隊,w=NextNeighbor,沒有鄰接頂點了所以跳出~~
此時
visited陣列:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
---|---|---|---|---|---|---|---|---|
visited | true | true | false | false | false | true | false | false |
隊: 1,6 ,隊頭為1,所以u為1
d[]和path[]陣列
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
---|---|---|---|---|---|---|---|---|
d[] | 1 | 0 | false | false | false | 1 | false | false |
path[] | 2 | -1 | -1 | -1 | -1 | 2 | -1 | -1 |
第二次while
1出隊~~
進入for迴圈~~
第一次for,u為1,第一個鄰接頂點為2,但是2已被訪問,所以不執行if內語句,w=NextNeighbor,還有鄰接頂點,所以繼續~~
第二次for,第二個u的鄰接頂點,為5,5尚未訪問所以路徑長度加1,此時因為d[u]初始為1,所以為1+1=2,最短路徑為u到w,即1到5,標記5已訪問,5入隊,w=NextNeighbor,沒有鄰接頂點了所以跳出~~
此時
visited陣列:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
---|---|---|---|---|---|---|---|---|
visited | true | true | false | false | true | true | false | false |
隊: 6 ,5,隊頭為6,所以u為6
d[]和path[]陣列
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
---|---|---|---|---|---|---|---|---|
d[] | 1 | 0 | false | false | 2 | 1 | false | false |
path[] | 2 | -1 | -1 | -1 | 1 | 2 | -1 | -1 |
第三次while~~
6出隊,再進行for迴圈,那麼之後就會變成~~
visited陣列:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
---|---|---|---|---|---|---|---|---|
visited | true | true | true | false | true | true | true | false |
隊: 5,3,7隊頭為5,所以u為5
d[]和path[]陣列
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
---|---|---|---|---|---|---|---|---|
d[] | 1 | 0 | 2 | false | 2 | 1 | 2 | false |
path[] | 2 | -1 | 6 | -1 | 1 | 2 | 6 | -1 |
第四次whlie~~
5,出隊,再進行for,沒有鄰接頂點,所以沒有改變~~
visited陣列:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
---|---|---|---|---|---|---|---|---|
visited | true | true | true | false | true | true | true | false |
隊: 3,7隊頭為3,所以u為3
d[]和path[]陣列
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
---|---|---|---|---|---|---|---|---|
d[] | 1 | 0 | 2 | false | 2 | 1 | 2 | false |
path[] | 2 | -1 | 6 | -1 | 1 | 2 | 6 | -1 |
第五次while~~
3出隊,進行for,此時~~
visited陣列:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
---|---|---|---|---|---|---|---|---|
visited | true | true | true | true | true | true | true | false |
隊: 7隊頭為7,所以u為7
d[]和path[]陣列
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
---|---|---|---|---|---|---|---|---|
d[] | 1 | 0 | 2 | 3 | 2 | 1 | 2 | false |
path[] | 2 | -1 | 6 | 3 | 1 | 2 | 6 | -1 |
第六次whlie~~
7出隊,進行for,此時~~
visited陣列:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
---|---|---|---|---|---|---|---|---|
visited | true | true | true | true | true | true | true | true |
隊: 沒有元素入隊,隊空了~~
d[]和path[]陣列
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
---|---|---|---|---|---|---|---|---|
d[] | 1 | 0 | 2 | 3 | 2 | 1 | 2 | 3 |
path[] | 2 | -1 | 6 | 3 | 1 | 2 | 6 | 7 |
此時隊空,跳出while,執行成功~~
此時,我們得到了d[]和path[]陣列~~
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
---|---|---|---|---|---|---|---|---|
d[] | 1 | 0 | 2 | 3 | 2 | 1 | 2 | 3 |
path[] | 2 | -1 | 6 | 3 | 1 | 2 | 6 | 7 |
比如我們看4號元素,即可知~~
2到4號元素的最短路徑為長度d[4] = 3;
2到4號元素的最短路徑為: 看4號元素path[4]為3,4 <- 3,再看3號元素path[3]為6,3 <- 6 ,再看6號元素path[6]為2,6 <- 2,所以2到4的最短路徑為:2 -> 6 -> 3 -> 4~~
寫到這才發現一寫就挺多的,那Dijkstra,Floyd演算法就下次再寫咯~~