㈠ 圖遍歷演算法之DFS/BFS
在計算機科學, 圖遍歷(Tree Traversal,也稱圖搜索)是一系列圖搜索的演算法, 是單次訪問樹結構類型數據(tree data structure)中每個節點以便檢查或更新的一系列機制。圖遍歷演算法可以按照節點訪問順序進行分類,根據訪問目的或使用場景的不同,演算法大致可分為28種:
圖遍歷即以特定方式訪問圖中所有節點,給定節點下有多種可能的搜索路徑。假定以順序方式進行(非並行),還未訪問的節點就需通過堆棧(LIFO)或隊列(FIFO)規則來確定訪問先後。由於樹結構是一種遞歸的數據結構,在清晰的定義下,未訪問節點可存儲在調用堆棧中。本文介紹了圖遍歷領域最流行的廣度優先搜索演算法BFS和深度優先搜索演算法DFS,對其原理、應用及實現進行了闡述。通常意義上而言,深度優先搜索(DFS)通過遞歸調用堆棧比較容易實現,廣義優先搜索通過隊列實現。
深度優先搜索(DFS)是用於遍歷或搜索圖數據結構的演算法,該演算法從根節點開始(圖搜索時可選擇任意節點作為根節點)沿著每個分支進行搜索,分支搜索結束後在進行回溯。在進入下一節點之前,樹的搜索盡可能的加深。
DFS的搜索演算法如下(以二叉樹為例):假定根節點(圖的任意節點可作為根節點)標記為 ,
(L) : 遞歸遍歷左子樹,並在節點 結束。
(R): 遞歸遍歷右子樹,並在節點 結束。
(N): 訪問節點 。
這些步驟可以以任意次序排列。如果(L)在(R)之前,則該過程稱為從左到右的遍歷;反之,則稱為從右到左的遍歷。根據訪問次序的不同,深度優先搜索可分為 pre-order、in-order、out-order以及post-order遍歷方式。
(a)檢查當前節點是否為空;
(b)展示根節點或當前節點數據;
(c)遞歸調用pre-order函數遍歷左子樹;
(d)遞歸調用pre-order函數遍歷右子樹。
pre-order遍歷屬於拓撲排序後的遍歷,父節點總是在任何子節點之前被訪問。該遍歷方式的圖示如下:
遍歷次序依次為:F -B -A-D- C-E-G- I-H.
(a)檢查當前節點是否為空;
(b)遞歸調用in-order函數遍歷左子樹;
(c)展示根節點或當前節點數據;
(d)遞歸調用in-order函數遍歷右子樹。
在二叉樹搜索中,in-order遍歷以排序順序訪問節點數據。該遍歷方式的圖示如下:
遍歷次序依次為:A -B - C - D - E - F - G -H-I
(a)檢查當前節點是否為空;
(b)遞歸調用out-order函數遍歷右子樹;
(c)展示根節點或當前節點數據;
(d)遞歸調用out-order函數遍歷左子樹。
該遍歷方式與LNR類似,但先遍歷右子樹後遍歷左子樹。仍然以圖2為例,遍歷次序依次為:H- I-G- F- B- E- D- C- A.
(a)檢查當前節點是否為空;
(b)遞歸調用post-order函數遍歷左子樹;
(c)遞歸調用post-order函數遍歷右子樹;
(d)展示根節點或當前節點數據。
post-order遍歷圖示如下:
遍歷次序依次為:A-C-E-D-B-H-I-G-F.
pre-order遍歷方式使用場景:用於創建樹或圖的副本;
in-order遍歷使用場景:二叉樹遍歷;
post-order遍歷使用場景:刪除樹
遍歷追蹤也稱樹的序列化,是所訪問根節點列表。無論是pre-order,in-order或是post-order都無法完整的描述樹特性。給定含有不同元素的樹結構,pre-order或post-order與in-order遍歷方式結合起來使用才可以描述樹的獨特性。
樹或圖形的訪問也可以按照節點所處的級別進行遍歷。在每次訪問下一層級節點之前,遍歷所在高層級的所有節點。BFS從根節點(圖的任意節點可作為根節點)出發,在移動到下一節點之前訪問所有相同深度水平的相鄰節點。
BFS的遍歷方法圖示如下:
遍歷次序依次為: F-B-G-A-D-I-C-E-H.
圖演算法相關的R包為igraph,主要包括圖的生成、圖計算等一系列演算法的實現。
使用方法:
參數說明:
示例:
結果展示:
DFS R輸出節點排序:
使用方法:
參數含義同dfs
示例:
結果展示:
BFS R輸出節點排序:
以尋找兩點之間的路徑為例,分別展示BFS及DFS的實現。圖示例如下:
示例:
輸出結果:
示例:
輸出結果:
[1] 維基網路: https://en.wikipedia.org/wiki/Tree_traversal
[2] GeeksforGeeks: https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/
[3] http://webdocs.cs.ualberta.ca/~holte/T26/tree-traversal.html
[4]Martin Broadhurst, Graph Algorithm: http://www.martinbroadhurst.com/Graph-algorithms.html#section_1_1
[5]igraph: https://igraph.org/r/doc/dfs.html
[6]igraph: https://igraph.org/r/doc/bfs.html
[7] Depth-First Search and Breadth-First Search in python: https://eddmann.com/posts/depth-first-search-and-breadth-first-search-in-python/
㈡ 如何修改基於dfs的演算法,使得可以避免對dfs生成的頂點序列進行逆序
可以把有限長非周期序列假設為一無限長周期序列的一個主直周期,即對有限長非周期序列進行周期延拓,延拓後的序列完全可以採用DFS進行處理,即採用復指數
第一題,DFS(深度優先遍歷)是一個遞歸演算法,在遍歷的過程中,先訪問的點被壓入棧底(棧是先進後出),再說:拓撲有序是指如果點U到點V有一條弧,則在拓撲序列中U一定在V之前。深度優先演算法搜索路徑恰恰是一條弧,棧的輸出是從最後一個被訪問點開始輸出,最後一個輸出的點是第一個被訪問的點。所以是逆的拓撲有序序列
第二題:無向圖路徑長度是指兩個頂點之間弧的條數,如果兩頂點路徑長度有2條弧,則有3個頂點例如A——B——C;
第三題:A:極小連通圖是一棵生成樹,只有N-1條邊,但是連通分量可能有N條邊,例如極小連通圖A—— B——C,連通分量「A」——B——C——「A」(這里的最後一個「A」跟第一個「A」一致):;