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 }

