DFS (Deep First Search)
概念:
顧名思義,這種遍歷方法是以深度爲優先進行對圖的搜索或者遍歷,至於什麼是以深度爲優先條件,先看下面DFS的基本步驟:
( 這是一個遞歸思想的DFS)
DFS:從當前節點開始,先標記當前節點,再尋找與當前節點相鄰,且未標記過的節點:
(1): 當前節點不存在下一個節點,則返回前一個節點進行DFS
(2): 當前節點存在下一個節點,則從下一個節點進行DFS
下面是圖解:
一開始,可以看出,若沒有走到死路,這種遍歷方式會從start節點沿着一條路一直深入下去(start -> 1 -> 2 -> 3。
若走到死路,便會退回上一節點,遍歷上一節點的其他相鄰節點(2 -> 4)。
這樣一直重複,直到找到終點。
所以跟你所見到的一樣,這樣的搜索方法像一根貪婪的蚯蚓,喜歡往深的地方鑽,所以就自然而然的叫做深度優先算法了。其用途也是非常多的,我覺得最直觀的用法之一是用來尋找迷宮的出口 。
我們可以順勢寫出DFS的僞代碼:
find(節點){
if(此結點已經遍歷 || 此節點在圖外 || 節點不滿足要求) return;
if(找到了end節點) 輸出結果 ; return;
標記此節點,表示已經遍歷過了;
while(存在下一個相鄰節點) find(下一個節點);
}
BFS (Breadth First Search)
概念:
對於深度優先算法,強迫症就很不爽了,並表示:“爲什麼不乾乾淨淨,一層一層地從start節點搜索下去呢,就像病毒感染一樣,這樣纔像正常的搜索的樣子嘛。”於是便有了BFS算法(誤)。廣度優先算法便如其名字,它是以廣度爲優先的,一層一層搜索下去的,就像病毒感染,擴散性的傳播下去。
圖解:
下圖中,start爲搜索的初始節點,end爲目標節點
我們先把star節點的關聯節點遍歷一次
接下來把第一步遍歷過的節點當成start,重複第一步
重複一二步,這樣便是一個放射樣式的搜哦防範,直到找到end節點
可以看出,這樣放射性的尋找方式,能找到從start到end的最近路(因爲每次只走一步,且把所有的可能都走了,誰先到end說
明這就是最短路)。但這樣如何用代碼實現?用棧貌似不行,改變遞歸的順序也不行。
這裏需要用到隊列:
a.比如每遍歷start周圍的一個“1”節點的時候,就把跟它相關聯的“2”節點保存到隊列中(“1”節點訪問完之後隊列內容:2,2,2,2)
b.然後依次訪問隊列內容,並對每個隊列元素重複a步驟(訪問一個“2”節點之後隊列的內容:2,2,2,3,3)。
c.由此重複下去,直到隊列爲空或者搜索到終點。
廣度優先的[遞歸]僞代碼如下:
把start節點push入隊列;
while(隊列不爲空) {
把隊列首節點pop出隊列;
對節點進行相關處理或者判斷;
while(此節點有下一個相關節點){
把相關節點push入對列;
}
}
應用例題:Abbott的復仇(Abbott's Revenge, ACM/ICPC World Finals 2000, UVa 816)