廣度優先搜尋與深度優先搜尋的差異:造訪順序、實作方式、最短路徑、記憶體與用途比較

兩者都是沿著邊,不遺漏地造訪圖或樹之頂點的搜尋方法。廣度優先搜尋(BFS)先造訪從起點走1條邊可到達的所有頂點,再到走2條邊可到達的頂點,依由近到遠的順序擴展。深度優先搜尋(DFS)沿著一條路盡可能地往前走,走到盡頭時就退回,改走另一條路。廣度優先搜尋以佇列實作,深度優先搜尋以堆疊或遞迴實作;若以鄰接串列表示圖,兩者都以與頂點數加邊數成正比的工夫造訪全部頂點。求無權重之圖的最短路徑時多用廣度優先搜尋,要窮舉所有路徑或偵測環路時多用深度優先搜尋。

項目廣度優先搜尋(BFS)深度優先搜尋(DFS)
造訪的順序依離起點由近到遠(經過的邊數由少到多)的順序,一層一層擴展沿一條路走到底,走到盡頭就退回,再走下一條路
使用的資料結構佇列(先進先出)堆疊(後進先出),或遞迴呼叫
最短路徑在邊沒有權重的圖中,第一次到達時經過的邊數,就是離起點的最短距離不保證最短。可能經由繞遠路的路徑先到達
時間複雜度(頂點數V、邊數E)鄰接串列為O(V + E),鄰接矩陣為O(V²)與廣度優先搜尋相同,鄰接串列為O(V + E),鄰接矩陣為O(V²)
使用的記憶體把接下來要造訪的頂點記在佇列中。分支多時,一整層的頂點會一起放進佇列,佇列會變大以遞迴撰寫時,只需記住目前路徑上的頂點,與路徑的深度成正比。太深時,呼叫堆疊可能溢位
能否找到解頂點有限時一定找得到。即使搜尋範圍無限擴展,也會從較淺位置的解依序找到在有限的圖中記錄已造訪的頂點,就一定找得到。路徑可能無限加深時,可能沿一條路一直走下去而不回頭
走訪樹的順序層序(從根開始逐層,由左到右)前序、中序、後序
主要用途無權重之圖的最短路徑、迷宮的最少步數、計算網路能到達幾跳之外迷宮或謎題的全部情形搜尋(回溯法)、偵測連通分量與環路、拓撲排序

數值為具代表性的大致參考值,會因世代或產品而異。

適用於什麼情況

廣度優先搜尋
想在邊沒有權重的圖中求最少步數或最短路徑時,或想從起點附近依序調查時。邊有權重時的最短路徑,要使用戴克斯特拉演算法。
深度優先搜尋
想窮舉所有路徑或組合時、想找出連通分量或環路時,以及決定作業順序的拓撲排序時。能以遞迴簡短地撰寫。

常見問題

邊有權重時,廣度優先搜尋也能求出最短路徑嗎?

不能。因為經過邊數最少的路徑,權重總和不一定最小。權重為0以上時,要使用戴克斯特拉演算法。戴克斯特拉演算法以「從離起點距離最小的頂點開始取出」的優先佇列取代佇列,也可以看成把廣度優先搜尋推廣到有權重的圖。

深度優先搜尋該用遞迴還是堆疊來寫?

以遞迴撰寫簡短易懂,但在非常深的圖中,呼叫層層疊加,可能使呼叫堆疊溢位。自行準備堆疊、以迴圈撰寫,就能避免這個問題。不過,依把相鄰頂點推入堆疊的順序,造訪順序可能與遞迴版本不同。

不記錄已造訪的頂點會怎樣?

在有環路的圖中,會一再造訪同一個頂點。廣度優先搜尋的佇列會無限變大,深度優先搜尋則可能在同一個環路上一直繞而無法結束。因此,不論哪種方法,都要為已造訪的頂點(或已放入佇列、堆疊的頂點)做記號,不再放入第二次。

理解度檢測

在邊沒有權重的圖中,想求出從起點到各頂點的最少邊數。適合的搜尋方法與所使用的資料結構組合為下列何者?

  1. A廣度優先搜尋與佇列
  2. B深度優先搜尋與堆疊
  3. C廣度優先搜尋與堆疊
查看答案與解析

正確答案:A. 廣度優先搜尋與佇列

廣度優先搜尋依由近到遠的順序拜訪:先是從起點經1條邊可到達的頂點,再來是經2條邊可到達的頂點……。把找到的頂點放入佇列尾端、從前端取出檢查,就能維持這個「由近到遠」的順序,因此第一次到達時的邊數就是最少的邊數。深度優先搜尋(使用遞迴或堆疊)會沿著一條路盡量往前走,可能先經由繞遠的路徑到達,不保證最短。若以堆疊取代佇列,走訪方式就會接近深度優先搜尋。

在無向圖中,各頂點的相鄰頂點如下:A: B, C / B: A, D, E / C: A, F / D: B / E: B, F / F: C, E。從頂點 A 進行遞迴的深度優先搜尋。相鄰頂點依此處列出的順序檢查,一找到尚未拜訪的頂點就立刻前往。拜訪頂點的順序為下列何者?

  1. AA, B, C, D, E, F
  2. BA, B, D, E, C, F
  3. CA, B, D, E, F, C
查看答案與解析

正確答案:C. A, B, D, E, F, C

從 A 前往 B,再前往 B 的相鄰頂點中第一個未拜訪的 D。D 的相鄰頂點只有已拜訪的 B,因此回到 B 再前往下一個 E,接著從 E 前往未拜訪的 F,再從 F 前往其相鄰頂點 C。所以順序為 A, B, D, E, F, C。A, B, C, D, E, F 是依離起點由近到遠拜訪的廣度優先搜尋的順序。A, B, D, E, C, F 沒有從 E 前往未拜訪的 F 就折返了,不是深度優先搜尋的順序。

像頂點約100萬個、邊約300萬條的道路網這樣,邊數相對於頂點數很少的(稀疏)圖,適合以下列何種方式存放在記憶體中?

  1. A鄰接矩陣。能以 O(1) 檢查兩個頂點之間是否有邊,記憶空間也最少
  2. B鄰接串列。記憶空間與頂點數加邊數的和成正比,適合依序走訪從某個頂點出發的邊
  3. C鄰接矩陣。記憶空間只與邊數成正比
查看答案與解析

正確答案:B. 鄰接串列。記憶空間與頂點數加邊數的和成正比,適合依序走訪從某個頂點出發的邊

鄰接矩陣對 V 個頂點使用 V×V 的表格,100萬個頂點需要10¹²個元素,即使每個元素1位元也約需125 GB。鄰接串列只列出與各頂點相連的頂點,因此記憶空間為 O(V + E),這個例子只需數百萬筆左右。鄰接矩陣的優點是能以 O(1) 檢查邊是否存在,適合邊多的(稠密)圖或頂點少的圖。對於像廣度優先搜尋或戴克斯特拉演算法這樣依序走訪從頂點出發之邊的處理,鄰接串列的效率較好。

  1. 在無向圖中,各邊的權重(距離)為 S−A: 4、S−B: 1、A−B: 2、A−C: 1、B−C: 5、C−T: 3、A−T: 6。以戴克斯特拉演算法求從 S 到 T 的最短路徑時,路徑與長度為下列何者?
  2. 對空的二元搜尋樹依序插入 50, 30, 70, 20, 40, 60, 80。以後序走訪(依左子樹、右子樹、該節點的順序拜訪)走訪此樹時,順序為下列何者?

前往資料結構與演算法的練習題

相關名詞的解說

廣度優先搜尋
依離起點由近到遠的順序(先是經1條邊可到達的頂點,再來是經2條邊可到達的頂點……)拜訪圖或樹的搜尋方法。以佇列實作,在邊沒有權重的圖中,能求出從起點到各頂點的最少邊數。取英文字首也稱為 BFS。
深度優先搜尋
沿著一條路盡量往前走,走到死路時折返再走另一條路,依此順序拜訪圖或樹的搜尋方法。以遞迴或堆疊實作,用於迷宮搜尋、連通元件與環路的偵測、拓撲排序等。取英文字首也稱為 DFS。
佇列
最先放入的元素最先取出的先進先出(FIFO)資料結構。放入尾端的操作稱為 enqueue,從前端取出的操作稱為 dequeue。用於等待處理的隊列、工作之間的資料傳遞、廣度優先搜尋等。
堆疊
最後放入的元素最先取出的後進先出(LIFO)資料結構。放入元素的操作稱為 push,取出的操作稱為 pop。用於管理函式呼叫的返回位址與區域變數(呼叫堆疊)、計算逆波蘭表示法的算式、深度優先搜尋等。
遞迴
函式在處理過程中呼叫自己。把問題分成形式相同的較小問題來解,並在不再分割的情況(基底情況)結束呼叫。每次呼叫都會使用堆疊,太深就會溢位。最後只呼叫自己的尾端遞迴可以轉換成迴圈。
戴克斯特拉演算法
在邊的權重都在0以上的圖中,求從一個起點到各頂點最短路徑的演算法。反覆確定距離尚未確定的頂點中最近的一個,並更新其相鄰頂點的距離。有負權重的邊時無法正確求出。
時間複雜度(大O符號)
表示演算法所需的工作量(時間複雜度)或記憶空間(空間複雜度),隨資料數 n 如何增加的指標。以 O(n)、O(n log n)、O(n²) 這類大O符號表示,省略係數與低次項。

相關的比較