參考網址: https://www.jianshu.com/p/60eb50dbfc39java
若是是遍歷一個數組,只須要從下標0到下標N-1循環就行了,遍歷一個鏈表只須要從頭指針開始直到沒有next爲止,即便是遍歷一棵樹,也能夠從根結點開始,按照前序、中序和後序等方式進行。之因此能夠這樣,是由於這些結構均可以找到一個明確的起點,但圖不一樣。以下圖所示,有的人但願從A開始遍歷,有的人喜歡從C開始...,沒有辦法規定一個明確的起點。git
若是沒有策略,遍歷一個圖就像走迷宮同樣,有可能在一個結點停留屢次,也可能有幾個結點永遠不會訪問到。而圖的遍歷,一般有深度優先和廣度優先方式,接下來咱們就看看這兩種方式是怎麼作的,有什麼區別。github
深度優先遍歷(Depth_First_Search)也稱爲深度優先搜索,簡稱爲DFS。它是從圖中某個頂點v出發,訪問此頂點,而後從v的未被訪問的鄰接點出發深度優先遍歷圖,直至圖中全部和v有路徑相通的頂點都被訪問到。對於非連通圖,只須要對它的連通份量分別進行深度優先遍歷便可。接下來咱們以一個示例演示圖的深度優先遍歷。以下圖所示:數組
在開始進行遍歷以前,咱們還要準備一個數組,用來記錄已經訪問過的元素。其中0表明未訪問,1表明已訪問,以下所示:spa
爲了便於演示,假設咱們是在走迷宮,A是入口,每次都向右手邊前進。首先從A走到B,結果以下:3d
B以後有三個路,咱們依然選擇最右邊,如此下去,直到走到F,以下所示:指針
到達F後,若是咱們繼續按照向右走的原則,就會再次訪問A,此時咱們訪問除了A後的最右側通道,也就是訪問G,以下所示:code
到達G後,能夠發現B和D都走過了,這時候走到H,以下所示:blog
到達H後,能夠發現D和E都走過了,也就是說走到了盡頭,可是並不表明全部的頂點都訪問過了,由於除了最右側頂點,每一個頂點還可能和更多的頂點連通,因此咱們從H退回到G,發現所有走過了,再向前退回到F,也所有走過了,直到退回到B時,發現 I 還沒走過,因而訪問頂點 I,以下所示:token
同理,訪問 I 以後,發現與 I 連通的頂點都訪問過了,因此再向前回退,直到回到頂點A,發現所有頂點都訪問過了,至此遍歷完畢。
深度優先遍歷能夠認爲是縱向遍歷圖,而廣度優先遍歷(Breadth_First_Search)則是橫向進行遍歷。還以上圖爲例,不過爲了方便查看,咱們把上圖調整爲以下樣式:
咱們依然以A爲起點,把和A鄰接的B和F放在第二層,把和B、F鄰接的C、I、G、E放在第三層,剩下的放在第四層。廣度優先遍歷就是從上到下一層一層進行遍歷,這和樹的層序遍歷很像。咱們依然藉助一個隊列來完成遍歷過程,由於和樹的層序遍歷很像,這裏只展現結果,以下所示:
對於非連通圖,依然經過visited數組來進行判斷便可。
圖的存儲方式有不少種,可是用來實現遍歷的思路是一致的,咱們以鄰接矩陣爲例,給出DFS和BFS的參考實現。
private void DFS(int i) { // 標記當前元素已經訪問 visited[i] = true; System.out.println("當前訪問頂點:" + getVertexByIndex(i)); int next = getFirstNeighbor(i); while (next != -1) { if (!visited[next]) { DFS(next); } next = getNextNeighbor(i, next); } } public void DFS() { for (int i = 0; i < vertexList.size(); i++) { visited[i] = false; } // 非連通圖,不一樣的連通份量要單獨進行DFS for (int i = 0; i < vertexList.size(); i++) { if (!visited[i]) { DFS(i); } } }
private void BFS(int i) { // 標記當前元素已經訪問 visited[i] = true; System.out.println("當前訪問頂點:" + getVertexByIndex(i)); int cur, next; LinkedList<Integer> queue = new LinkedList<>(); queue.addLast(i); while (!queue.isEmpty()) { cur = queue.removeFirst(); next = getFirstNeighbor(cur); while (next != -1) { if (!visited[next]) { // 標記當前元素已經訪問 visited[next] = true; System.out.println("當前訪問頂點:" + getVertexByIndex(next)); queue.addLast(next); } next = getNextNeighbor(cur, next); } } } public void BFS() { for (int i = 0; i < vertexList.size(); i++) { visited[i] = false; } for (int i = 0; i < vertexList.size(); i++) { if (!visited[i]) { BFS(i); } } }
完整代碼已上傳至個人github。