廣度優先搜尋(bfs),可以被形象的描述為「淺嘗輒止」,具體一點就是每個頂點只訪問它的鄰接節點(如果它的鄰接節點沒有被訪問)並且記錄這個鄰接節點,當訪問完它的鄰接節點之後就結束這個頂點的訪問。
廣度優先用到了「先進先出」佇列,通過這個佇列來儲存第一次發現的節點,以便下一次的處理;而對於再次發現的節點,我們不予理會——不放入佇列,因為再次發現的節點:
無非是已經處理完的了;
或者是儲存在佇列中尚未處理的。
《演算法導輪》對兩種搜尋都採用了很聰明的做法,用白色white來標誌未發現的節點,用灰色gray來標誌第一次被發現的節點,用黑色black來標誌第二次被發現的節點。
於是有了:
bfs(g,s)
for
each vertex v in v[g]
status[v] = white
/******其他初始化******/
status[s] = gray
//s是原點
queue q
入隊(q,s);
while
q非空
t = 出隊(q);
for
each vertex v in adj[t]
//與t鄰接的點
if
status[v] = white
//只對未訪問的操作
status[v] = gray
//標記為第一次訪問
/******其他操作******/
入隊(q,v)
status[t] = black
//此點已經處理完了
導輪還在上面偽**的「其他」中加入了訪問長度和父節點的操作。此舉可以算出,從源點到其他頂點路徑的最少步數和它的具體路徑。
關於廣度優先搜尋的乙個簡單應用:
假如有問題,每個村莊之間都通過橋來聯通,先給出村莊的圖,問村莊a到村莊b最少要通過多少座橋?這個問題可以很容易的轉化為上面的bfs問題。
深度優先搜尋(dfs),可以被形象的描述為「打破沙鍋問到底」,具體一點就是訪問乙個頂點之後,我繼而訪問它的下乙個鄰接的頂點,如此往復,直到當前頂點一被訪問或者它不存在鄰接的頂點。
同樣,演算法導論採用了「聰明的做法」,用三種顏色來標記三種狀態。但這三種狀態不同於廣度優先搜尋:
white 未訪問頂點
gray 一條深度搜尋路徑上的頂點,即被發現時
black 此頂點的鄰接頂點被全部訪問完之後——結束訪問次頂點
/******其他初始化******/
for
each vertex v in v(g)
if
(status[v]==white)
dfs-visit(v)
dfs-visit(v)
status[v] = gray
for
each vertex t in adj(v)
if
status[t] = white
dfs-visit(t)
/******其他操作******/
status[v] = black
通過給dfs搜尋過程中給每乙個頂點加時間戳,就可以實現拓撲排序了。實現拓撲排序需要:
對於每乙個頂點,都有兩個時間戳,分別這樣來定義:
在一頂點剛被發現的時候,標記此頂點的第乙個時間戳;
在結束此頂點的訪問的時候,標記此頂點的第二個時間戳。時間戳可以用簡單的123456來標記,只要能區分大小就行。
因此,你會發現,越早發現的點,他的第乙個時間戳會越小,但是他的第二個時間戳會越大。
兩個演算法都是o(v+e),在用到的時候適當選取。在使用白灰黑標誌的時候,突然明白了如何用深度優先搜尋來判斷有向圖中是否存在環。
深度優先和廣度優先各有各的優缺點:
在更多的情況下,深優是比較好的方案。
BFS和DFS的區別與分析
深度優先遍歷 對每乙個可能的分支路徑深入到不能再深入為止,而且每個結點只能訪問一次。要特別注意的是,二叉樹的深度優先遍歷比較特殊,可以細分為先序遍歷 中序遍歷 後序遍歷 我們前面使用的是先序遍歷 具體說明如下 先序遍歷 對任一子樹,先訪問根,然後遍歷其左子樹,最後遍歷其右子樹。中序遍歷 對任一子樹,...
bfs和dfs的特點
一 深度優先搜尋 dfs 的特點是 1 深度優先搜尋法有遞迴以及非遞迴兩種設計方法。一般的,當搜尋深度較小 問題遞迴方式比較明顯時,用遞迴方法設計好,它可以使得程式結構更簡捷易懂。當資料量較大時,由於系統堆疊容量的限制,遞迴容易產生溢位,用非遞迴方法設計比較好。2 深度優先搜尋方法有廣義和狹義兩種理...
dfs和bfs的應用
dfs 能找到可行的路徑,所需時間長,需要標記位置 bfs 能找到最短的路徑,所需空間長,需要出入佇列 兩個搜尋的相同點是都利用了二維陣列的圖,有的時候都用了標記方法。但是dfs,我覺得沒什麼變化,就這樣了。但是bfs,1.可以用stl的queue,但是,沒辦法對付路徑記錄。2.可以用自己寫的結構體...