最短路徑問題,BFS,408方向,思路與實現分析

ZaunEkko發表於2021-06-14

最短路徑問題,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演算法就下次再寫咯~~

相關文章