深度優先搜索(Depth-first search)是如何搜索一張圖的?

思想:對於最新發現的頂點v,若是它還有以此爲起點而還未探索的邊,沿此邊探索。若是v的全部邊已經探索完了,再回溯到發現v有起始點的那些邊。一直到已經探索了從源起點可到的全部頂點爲止。若是還有沒探索的頂點,將它定義爲一個新的源頂點,繼續上述過程。算法

像走迷宮同樣,嘗試每種可能的結果,沒走通,就回溯到當初分叉的路口,繼續探索bash

探索整個的圖

DFS(V,Adj):
    parent={}
    for s in V: //遍歷圖中全部的點
        if s not in parent: //點沒有遍歷過就繼續探索
            parent[s]=None //源點不設置父節點
            DFS-Visit(Adj,s) //探索當前源頂點可以到達的全部的點
複製代碼

給定一個源頂點s,DFS的實現方式

DFS-Visit(Adj,s):
   for v in Adj[s]: //遍歷全部的邊
       if v not in parent: //當前邊沒有遍歷過
           parent[v]=s //記錄已經遍歷
           DFS-Visit(adj,v) //優先探索當前節點的邊,完成以後,再執行回溯(經過循環實現)
複製代碼

以有向圖爲例
假設按照字母的順序來遍歷全部的頂點,即V=[a,b,c,d,e,f],原始的圖爲spa

  1. 第一步探索a到b的邊,發現b還有邊,一直往下走,直到d爲止,d沒有往下走的邊,第一個DFS-Visit執行結束

2. 開始回溯,先回溯到d的父節點e,一樣沒有,一直到a,a的另外一條邊是a到d,可是d已經探索過,再也不操做

3. 換源點執行探索,此時爲b,可是b已經探索過,再探索c發現僅一條邊對應的f沒探索過

  1. 繼續更換源點一直到f,都沒有新的還沒有探索過的邊,最終DFS探索生成了兩顆深度優先樹

深度優先樹指的是通過DFS生成的樹,結果爲3中的橙色箭頭所指的兩個部分.net

時間複雜度

O(V+E);它的遍歷規則仍然須要遍歷全部的節點一遍,對於每條變來說,只有沒有遍歷過的才作一次遍歷3d

深度優先搜索的用途是什麼?

1. 邊分類

  • 樹邊。若是頂點v是在探尋邊(u,v)首次發現的,那麼(u,v)是樹邊,好比圖中(a,b)
  • 正向邊。u到v的某個非樹邊,好比圖中(a,d),a到d存在邊,可是沒有進入樹中
  • 反邊。 鏈接u到它的祖先頂點v的邊,好比圖中的(d,b)
  • 交叉邊。生成的樹中,兩個頂點不存在父子關係。好比圖中的 (g,d)

在算法中,樹邊判斷經過parent就能夠看出,parent的逆向就是樹邊,得以標識;code

反邊判斷,能夠在源點開始作一個標記,把全部的通過的節點都放入棧中,若是下次獲得的頂點在棧中,那麼這條邊就是反邊;cdn

如何判斷在一個圖中是否存在環?

圖G存在環,當且僅當圖中存在一條反邊。證實以下:blog

  • 存在環,證實有反邊。假設從環中選取一個點v_0,做爲DFS遍歷的第一個頂點,證實 (v_k,v_0)是反邊:已知事實是,v_1訪問前,v_0一定已經訪問完,v_k訪問前,v_0一定已經訪問完,當訪問到v_k再下一個查看v_0的時候,v_0已經在棧中,那麼(v_k,v_0)是反邊

  • 存在反邊,證實有環。首先s到t必然存在樹邊,而後t到s是一條反邊,那必然成環

2. Job調度

Job自己是個無環的有向圖,各個頂點之間一定存在着必定的順序,執行的時候等前面的執行完才能再執行排在後面的排序

它使用的算法稱做拓撲排序,拓撲排序內部使用的就是DFS,輸出爲完成時的頂點的逆序,就排序好了(以前記錄的是parent的指向,真正的執行是先parent)it

這種排序產生的結果是,假設圖中全部的頂點放在同一個水平線上,那麼全部的方向均是從左到右

證實

只須要證實,對於任何一個邊e=(u,v),在v執行完以後,u才執行完

  • u的訪問發生在v以前:因爲u,v之間存在一條邊,那麼在u執行完以前,確定爲訪問v,而等v完成後,才能完成u
  • v的訪問在u以前:因爲u和v之間存在一條邊,若是先訪問了v,若是存在v到u的路徑,這樣會有環,因此根本不會執行u,也就是說,v先執行完

附錄

算法導論(MIT 6.006 第14講)

相關文章
相關標籤/搜索