我們知道,演算法是作用於具體資料結構之上的,深度優先搜尋演算法和廣度優先搜尋演算法都是基於「圖」這種資料結構的。這是因為,圖這種資料結構的表達能力很強,大部分涉及搜尋的場景都可以抽象成「圖」。
無向圖的**實現
public廣度優先搜尋class graph
} public
void addedge(int s, int t)
}
廣度優先搜尋(breadth-first-search),我們平常都把簡稱為 bfs。直觀地講,它其實就是一種「地毯式」層層推進的搜尋策略,即先查詢離起始頂點最近的,然後是次近的,依次往外搜尋。理解起來並不難,所以我畫了一張示意圖,你可以看下。
**實現
publicvisited 是用來記錄已經被訪問的頂點,用來避免頂點被重複訪問。如果頂點 q 被訪問,那相應的 visited[q] 會被設定為 true。void bfs(int s, int
t)
while (queue.size() != 0)
visited[q] = true
; queue.add(q);}}
}}private
void print(int prev, int s, int t)
system.out.print(t + " ");
}
queue 是乙個佇列,用來儲存已經被訪問、但相連的頂點還沒有被訪問的頂點。因為廣度優先搜尋是逐層訪問的,也就是說,我們只有把第 k 層的頂點都訪問完成之後,才能訪問第 k+1 層的頂點。當我們訪問到第 k 層的頂點的時候,我們需要把第 k 層的頂點記錄下來,稍後才能通過第 k 層的頂點來找第 k+1 層的頂點。所以,我們用這個佇列來實現記錄的功能。
prev 用來記錄搜尋路徑。當我們從頂點 s 開始,廣度優先搜尋到頂點 t 後,prev 陣列中儲存的就是搜尋的路徑。不過,這個路徑是反向儲存的。prev[w] 儲存的是,頂點 w 是從哪個前驅頂點遍歷過來的。比如,我們通過頂點 2 的鄰接表訪問到頂點 3,那 prev[3] 就等於 2。為了正向列印出路徑,我們需要遞迴地來列印,你可以看下 print() 函式的實現方式。
圖示廣度搜尋
深度優先搜尋
假設你站在迷宮的某個岔路口,然後想找到出口。你隨意選擇乙個岔路口來走,走著走著發現走不通的時候,你就回退到上乙個岔路口,重新選擇一條路繼續走,直到最終找到出口。這種走法就是一種深度優先搜尋策略。
實際上,深度優先搜尋用的是一種比較著名的演算法思想,回溯思想。這種思想解決問題的過程,非常適合用遞迴來實現。
**boolean found = false; //
全域性變數或者類成員變數
public這段**的關鍵點在於把每個訪問點的座標都記錄了,即使1-2-3路徑然後沒路了,仍然可以遞迴彈棧到頂點5處再進行for迴圈走。void dfs(int s, int
t) recurdfs(s, t, visited, prev);
print(prev, s, t);
}private
void recurdfs(int w, int t, boolean visited, int
prev)
for (int i = 0; i < adj[w].size(); ++i)
}}
對於三度好友關係問題,首選廣度搜尋。
廣度優先搜尋,通俗的理解就是,地毯式層層推進,從起始頂點開始,依次往外遍歷。廣度優先搜尋需要借助佇列來實現,遍歷得到的路徑就是,起始頂點到終止頂點的最短路徑。深度優先搜尋用的是回溯思想,非常適合用遞迴實現。換種說法,深度優先搜尋是借助棧來實現的。在執行效率方面,深度優先和廣度優先搜尋的時間複雜度都是 o(e),空間複雜度是 o(v)。
深度優先搜尋和廣度優先搜尋
深度優先的思想是先記住當前的起點,然後選定乙個方向一條道走到黑,若失敗則回到起點再選定另外乙個方向走到黑。廣度優先的思想是記住當前的起點,然後選定各個方向的相鄰點作為新的起點,再繼續。可以看出,深度優先和廣度優先都需要記住當前的起點,不同的是深度優先每次只需要記住乙個方向的相鄰點,廣度優先則要記住所...
廣度優先搜尋和深度優先搜尋
dbf深度優先搜尋,最經典的方法,可以使用遞迴來實現。結構體定義 typedef char vertextype typedef int edgetype define maxvex 100 define infinite 65535 typedef struct mgraph 測試函式如下 mgr...
深度優先搜尋和廣度優先搜尋
定義 圖 graph 是由頂點的有窮非空集合和頂點之間邊的集合組成,通常表示為 g v,e 其中,g表示乙個圖,v是圖g中頂點的集合,e是圖g中邊的集合.簡單點的說 圖由節點和邊組成。乙個節點可能與眾多節點直接相連,這些節點被稱為鄰居。如二叉樹就為乙個簡單的圖 廣度優先搜尋演算法 breadth f...