1. 程式人生 > >常用算法之——廣度優先搜索

常用算法之——廣度優先搜索

isempty tails fontsize 過程 tail 決定 爸爸 一個 這樣的

轉載。 https://blog.csdn.net/m0_37316917/article/details/70879977

廣度優先搜索的概念

 廣度優先搜索(BFS)類似於二叉樹的層序遍歷算法,它的基本思想是:首先訪問起始頂點v,然後由v出發,依次訪問v的各個未被訪問過的鄰接頂點w1,w2,w3….wn,然後再依次訪問w1,w2,…,wi的所有未被訪問過的鄰接頂點,再從這些訪問過的頂點出發,再訪問它們所有未被訪問過的鄰接頂點….以此類推,直到途中所有的頂點都被訪問過為止。類似的想法還將應用與Dijkstra單源最短路徑算法和Prim最小生成樹算法。(這個過程我覺得可以舉個這樣的例子來理解:比如要從你開始介紹你的家人,可以先從你開始,然後一個一個介紹和你有直接血緣關系的這一層親屬(爸爸媽媽兒子女兒),當把你所有的這些第一層親屬全都遍歷完之後再從你的媽媽開始遍歷(也可以從爸爸或兒子),把你媽媽的有直接血緣關系的親戚先遍歷一遍,然後再從爸爸開始,以此類推,直到全部都遍歷完成

)。
 廣度優先搜索是一種分層的查找過程,每向前走一步可能訪問一批頂點,不像深度優先搜索那樣有回退的情況(另一篇博客會介紹),因此它不是一個遞歸的算法,為了實現逐層的訪問,算法必須借助一個輔助隊列並且以非遞歸的形式來實現。

算法偽代碼

其偽代碼如下:
 

bool visited[MAX_VERTEX_NUM];//訪問數組,也就是頂點個數

void BFSTraverse(Graph G)
//外層的函數,為準備實現遍歷做一些準備工作。
{
 forint i=0;i<G.vexnum;++i)
     visited[i]=false;//先將所有的頂點都設置為沒有被訪問過
InitQueue(Q);//初始化輔助隊列方便遍歷頂點 for(int i=0;i<G.vexnum;++i) if(!visited[i]) BFS(G,i); //外層循環使用if語句來調用BFS的原因是為了防止有的頂點它不能從初始頂點出發而遍歷到,所以這裏需要一個完全的循環來避免這種極端情況。 } void BFS(Graph G,int v) //從頂點v出發,廣度優先遍歷圖G,算法借助了一個輔助隊列Q visit(v);//visit函數訪問這個頂點的信息 visited[v]=true;//訪問過了這個頂點之後就將這個頂點設置為已訪問,即true
Enqueue(Q,v);//將頂點v入隊列,這樣就可以從隊列中出隊並訪問它的相鄰頂點 while(!isEmpty(Q)){ DeQueue(Q,v);//將隊頭的元素出隊列存儲在v for(w=FirstNeighbor(G,v);w>=0;w=NextNeighbor(G,v,w))//這一步是檢查v的所有鄰接頂點 if(!visited[w]){ visit(w); visited[w]=true; EnQueue(Q,w); //如果w沒有被訪問過,那麽訪問這個頂點,並把它入隊 } }

實例以及解析

技術分享圖片
  假設從a頂點開始訪問,a先入隊。此時隊列非空,取出隊頭元素a,由於b,c和a直接相鄰且未被訪問過,於是依次訪問b,c,並且b,c依次入隊。隊列非空,取出隊頭元素b,依次訪問與b相鄰且未被訪問的頂點d,e,並且將d,e入隊(註意:a與b也鄰接,但是a已經訪問過,就不會再訪問了)。此時隊列非空,取出隊頭元素c,訪問與c鄰接且未被訪問過的頂點f,g,並且將f,g入隊。此時,取出隊頭元素d,但與d鄰接且為被訪問的頂點為空,故不再進行任何操作,繼續取出對頭元素e,將h入隊….當最後取出隊頭元素h後,隊列為空,從而循環自動跳出,遍歷的結果為abcdefgh。

BFS算法性能分析

  無論是鄰接表還是鄰接矩陣的存儲訪問,BFS算法都需要借助一個輔助隊列Q,n個頂點都需要入隊依次,在最壞的情況下,空間復雜度為O(|V|)
  當采用鄰接表存儲方式時,每個頂點均需要搜索依次(或入隊依次),故時間復雜度為O(|V|),再搜索任一頂點時,每條邊至少訪問依次,故時間復雜度為O(|E|),算法的總時間復雜度為O(|V|+|E|);當采用鄰接矩陣存儲方式的時候,查找每個頂點的鄰接點所需時間為O(|V|),故算法總的時間復雜度為O(|V|²)

BFS算法求單源最短路徑問題

  如果圖G=(V,E)為非帶權圖。定義從頂點u到頂點v的最短路徑d(u,v)為從u到v的任何路徑中最少的邊數;如果從u到v沒有通路,則d(u,v)=∞。
  使用BFS,我們可以求解一個滿足上述定義的非帶權圖的單源最短路徑問題,這是由廣度優先搜索總是按照距離由近到遠來遍歷圖中每個頂點的性質決定的(這讓我想到:在2d遊戲中計算兩個位置的最短路徑是否可以采用BFS算法來求出呢?
  BFS算法求解單源最短路徑問題的算法如下:
  

void BFS_MIN_Distance(Graph G,int u){
//d[i]表示從u到i結點的最短路徑
    for(i=0;i<G.vexnum;++i)
        d[i]=∞; //初始化路徑長度
    visited[u]=true;
    d[u]=0;
    while(!isEmpty(Q)){
    DeQueue(Q,u);
    for(w=FirstNeighbor(G,u);w>=0;w=NextNeighbor(G,u,w))
    if(!visited[w]){//w為u未曾訪問的鄰接頂點
    visited[w]=true;//設為已經訪問
    d[w]=d[u]+1;//路徑長度+1
    EnQueque(Q,w);//w頂點入隊
    }

    }
}

常用算法之——廣度優先搜索