1.深度優先遍歷(DFS)

圖的深度優先遍歷本質上是一棵樹的前序遍歷(即先遍歷自身,然後遍歷其左子樹,再遍歷右子樹),總之圖的深度優先遍歷是一個遞迴的過程。

如下圖所示,左圖是一個圖,右圖是圖的深度優先遍歷過程。我們假設從頂點A開始遍歷,A被標記後,A面前有兩個頂點B和F可以選擇,我們該選擇哪個呢?這裡我們可以假設每次都選擇最右邊的頂點,因此我們選擇B頂點,B被標記後,緊接著有C、I、G三個頂點可選擇(如右圖的B節點下有三個子節點C、I、G),還按照最右邊原則,我們選擇C頂點進行遍歷。

以此類推遍歷到H頂點時(參考右圖),我們發現到F頂點時,其最右邊的A頂點已經被標記過,因此選擇第二右的G頂點。到頂點H時,我們發現H後面的D和E頂點都已經被我們標記過,現在已經無路可走,但此時並沒有結束,因為還有個I頂點還沒有被遍歷,這時候我們就要回溯,就好像樹的前序遍歷一樣,左子樹遍歷完會回溯到root節點,接著遍歷其右子樹。我們從H頂點回溯到G頂點,檢查G的三個頂點B、D、H是否有沒有被遍歷的,發現都已經被遍歷,那麼我們繼續往上回溯,發現回溯到D頂點時,與其相連的四個頂點中,I頂點沒有被遍歷,接著就遍歷I頂點,遍歷完後繼續回溯,知道回溯到最初的A頂點,演算法結束。

 程式碼部分:

我們用一個類MGrapg01表示鄰接矩陣,其中包括鄰接矩陣的建立方法(此處省略,鄰接矩陣的建立可參考上一篇文章)。

其中DFS演算法由DFS_map和DFS兩個方法構成,其中DFS_Map用來從起始點開始深度優先遍歷,DFS()方法完成深度優先遞迴操作。並且用一個visit陣列來表示頂點被遍歷的狀態,若頂點被遍歷,則被標記為true,否則為false。

程式碼是無向圖的深度遍歷,對於有向圖而言,它只是通道存在可行與不可行,演算法上是沒有變化的,這裡完全可以通用。

 1 public class MGraph01 {
2 public int numNodes; //圖的頂點數目
3 public int numEdges; //圖的邊數
4 public Object[] vexs; //一維頂點陣列
5 public int[][] arcs; //二維邊陣列
6 public static final int INF = Integer.MAX_VALUE; //無窮大
7
8
9 /**
10 *此處省略鄰接矩陣的建立程式碼,可參考第一篇文章
11 /
12
13 /**
14 * 深度優先遍歷操作
15 */
16 public void DFS_Map() {
17 //初始化陣列,每個值為false,預設為未訪問狀態
18 boolean[] visit = new boolean[numNodes];
19 for (int i = 0; i < visit.length; i++) {
20 if (!visit[i]) {
21 DFS(i, visit);
22 }
23 }
24 }
25
26 /**
27 * 無向圖的深度優先遞迴演算法
28 *
29 * @param i
30 */
31 private void DFS(int i, boolean[] visit) {
32 visit[i] = true;
33 System.out.println("頂點" + vexs[i] + "已被遍歷");
34 for (int j = 0; j < numNodes; j++) {
35 //對未被訪問的頂點遞迴呼叫
36 if (!visit[j] && arcs[i][j] == 1) {
37 DFS(j, visit);
38 }
39 }
40 }
41 }

程式碼測試: 

 1 public class MGraph01Test {
2 public static void main(String[] args) {
3 //初始化一個鄰接矩陣物件
4 MGraph01 graph01 = new MGraph01();
5 //呼叫createUDG方法來建立無向圖的鄰接矩陣
6 graph01.createUDG();
7 //呼叫深度優先遍歷方法
8 graph01.DFS_Map();
9 }
10 }