廣度優先搜索算法(Breath-first Search)是如何搜索一張圖的?

算法導論(MIT 6.006 第13講)算法

什麼是圖搜索?

搜索能夠理解爲探索,給定一個圖上的點S和A,須要找到從S到A的一個路徑數組

圖的基礎概念

一個圖用 G=(V,E) 表示,V是頂點的集合,E是邊的集合。以下所示有兩種圖bash

  1. 無向圖,V={a,b,c},E={{a,b},{b,c},{a,c}}

2. 有向圖,V={a,b,c},E={(a,b),(b,a),(c,a),(b,c)}

實際應用有哪些?

網絡爬蟲、社交網絡、網絡包傳播、垃圾回收算法等網絡

如何用算法表示圖?

使用鄰接表。它是一個數組(Adj表示)大小是 |V|,每一個元素是指向一個鏈表的指針,遍歷的方法以下app

for each vertex u in V
    Adj[u] stores u's neighbors 複製代碼

好比,上所述的有向圖來講 Adj[a]={b},Adj[b]={a,c},對無向圖來說 Adj[a]={(a,c),(a,b)}spa

這種表現形式所須要的空間大小爲 \Theta(V+E),|V|個頂點和|E|條邊.net

廣度優先算法是如何搜索一張圖的?

目標:對於一個給定的節點S \inV,經過它來遍歷它所能到達的全部節點
時間要求:O(V+E)
思路:查看給定節點,經過0步移動,可以到達的節點,這個節點就是s自己,而後從s移動一步,也就是s的鄰接表,找到他能到達的節點,依次類推,須要避免重複3d

BFS(s,Adj):
    level={s:0} //第0步能到達的節點
    parent={s:None}
    i=1 //第0步就是s,已經到達,從第一步開始
    frontier=[s] //前一層已經通過的節點 level=i-1
    while frontier: //在已經通過的節點找它的相鄰節點
        next=[] //當前層找到的節點
        for u in frontier:
            for v in Adj[u]:
                if  v not in level: //當前節點沒有在其它層出現過,從而避免重複
                    level[v]=i 
                    parent[v]=u
                    next.append(v)
        frontier=next 
        i+=1 //走下一層
複製代碼

以無向圖爲例指針

  1. 初始狀態,處於第0層,i=0,s沒有父節點,已經通過的節點只有s

2. 從s移動0步,s的相鄰節點是a和x,他們沒有在以前的level存在,因此須要添加到level中。執行完後

level={s:0,a:1,x:1}  
parent={s:None,a:s,x:s}  
frontier={a,s}  
i=2
複製代碼

3. 以新的frontier爲基礎,再往前一步,發現a有z和s,可是s已經經歷過了,再也不添加,依次類推x。執行完以後

level={s:0,a:1,x:1,z:2,x:2}  
parent={s:None,a:s,x:s,z:a,d:x,c:x}  
frontier={z,d,c}  
i=3
複製代碼

  1. 以新的frontier爲基礎,再往前一步,發現z的惟一鄰接節點只有a,可是a已經在level 1中,再也不添加。執行完以後
level={s:0,a:1,x:1,z:2,x:2,f:3,v:3}  
parent={s:None,a:s,x:s,z:a,d:x,c:x,f:d,v:c} frontier優先存的是d  
frontier={f,v}  
i=4
複製代碼

5. 以新的frontier爲基礎,再往前一步,發現f,v的鄰接節點都已經計算過,再也不計入,所以最後

frointer={}  
i=5
複製代碼

至此結束code

耗時分析

BFS所作的策略是先找到每一層的節點,再去找它的鄰接表,耗時能夠從兩部分來看,1個是必須遍歷全部節點,爲V,另外每一層遍歷的邊的數量爲 \sumv\inV|Adj[v]|,即每一個頂點的邊的個數,對於有向圖來說是E,無向圖就是2E,這樣總的時間就是 \theta(V+E)

優勢

  1. 當想知道某個節點到原點s的最短路徑時,能夠直接從level上獲取,而且parent提供的指針就是這條路徑
  2. 能直接感知到從s可否到達某個節點t
相關文章
相關標籤/搜索