BFS和DFS的簡要分析

2021-07-04 20:32:28 字數 2894 閱讀 7735

廣度優先搜尋(bfs),可以被形象的描述為「淺嘗輒止」,具體一點就是每個頂點只訪問它的鄰接節點(如果它的鄰接節點沒有被訪問)並且記錄這個鄰接節點,當訪問完它的鄰接節點之後就結束這個頂點的訪問。

廣度優先用到了「先進先出」佇列,通過這個佇列來儲存第一次發現的節點,以便下一次的處理;而對於再次發現的節點,我們不予理會——不放入佇列,因為再次發現的節點:

無非是已經處理完的了;

或者是儲存在佇列中尚未處理的。

《演算法導輪》對兩種搜尋都採用了很聰明的做法,用白色white來標誌未發現的節點,用灰色gray來標誌第一次被發現的節點,用黑色black來標誌第二次被發現的節點。

於是有了:

bfs(g,s)

foreach vertex v in v[g]

status[v] = white

/******其他初始化******/

status[s] = gray//s是原點

queue q

入隊(q,s);

whileq非空

t = 出隊(q);

foreach vertex v in adj[t]//與t鄰接的點

ifstatus[v] = white//只對未訪問的操作

status[v] = gray//標記為第一次訪問

/******其他操作******/

入隊(q,v)

status[t] = black//此點已經處理完了

導輪還在上面偽**的「其他」中加入了訪問長度和父節點的操作。此舉可以算出,從源點到其他頂點路徑的最少步數和它的具體路徑。

關於廣度優先搜尋的乙個簡單應用:

假如有問題,每個村莊之間都通過橋來聯通,先給出村莊的圖,問村莊a到村莊b最少要通過多少座橋?這個問題可以很容易的轉化為上面的bfs問題。

深度優先搜尋(dfs),可以被形象的描述為「打破沙鍋問到底」,具體一點就是訪問乙個頂點之後,我繼而訪問它的下乙個鄰接的頂點,如此往復,直到當前頂點一被訪問或者它不存在鄰接的頂點。

同樣,演算法導論採用了「聰明的做法」,用三種顏色來標記三種狀態。但這三種狀態不同於廣度優先搜尋:

white 未訪問頂點

gray 一條深度搜尋路徑上的頂點,即被發現時

black 此頂點的鄰接頂點被全部訪問完之後——結束訪問次頂點

/******其他初始化******/

foreach vertex v in v(g)

if(status[v]==white)

dfs-visit(v)

dfs-visit(v)

status[v] = gray

foreach vertex t in adj(v)

ifstatus[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.可以用自己寫的結構體...