資料結構之深度優先遍歷
阿新 • • 發佈:2019-01-23
深度優先遍歷(DSF):
思想:可以使用遞迴和非遞迴來完成dsf
簡述一下非遞迴方法的思想:是使用佇列還是棧呢?首先要明確佇列和棧各自的特點,佇列是先進先出,棧是後進先出出,想一想深度優先檢索,重點是在深度,要想深度向下,就需要沿著一條線從一個節點一直向下
遍歷直到沒有節點可遍歷位置。那麼問題來了,要想沿著一條線不斷向下,就需要不斷的找起始節點的下一個節點
再下一個節點,再再下一個節點......直到最後,可以通過一個節點的鄰接節點來找到其“下一個節點”,
所以使用棧,從第一個節點開始,不斷的入棧彈棧,利用棧的後進先出的特點來找出節點的某一鄰接節點作為
遍歷路徑上的下一個節點
接下來上張圖來說明深度遍歷
再看B的鄰接節點有C,I,G選擇C作為B的下一個節點,此時B也已經遍歷過了,一次類推比如遍歷的順序為A,B,C,D,E,F,G,H,
沒有能往下繼續遍歷的節點,所以開始回溯,看是否還有節點沒有遍歷完,首先回溯到節點G,發現G的鄰接節點已經
完全遍歷完了,在回溯到F,同樣如此,然後F,E,D,C依次回溯,到C發現C的鄰接節點I沒有遍歷,所以把I作為下一個節點開始遍歷
,遍歷完再回溯,直達回溯到A節點為止。所以應為再回溯的過程中要找上一個節點,所以用棧非常適合深度優先遍歷
深度優先遍歷既可以使用遞迴方法又可以使用非遞迴方法
下面呈上一段詳細程式碼
package SevenProvience.tital2; import java.util.Stack; public class DFS { //儲存節點資訊 private char[] vertices; //儲存邊資訊(鄰接矩陣) private int[][] arcs; //圖的節點數 private int vexnum; //記錄節點是否已被遍歷 private boolean[] visited; //初始化 public DFS(int n){ vexnum=n; vertices=new char[n]; arcs=new int[n][n]; visited=new boolean[n]; //將矩陣所有的邊都初始化為0 for(int i=0;i<vexnum;i++){ for(int j=0;j<vexnum;j++){ arcs[i][j]=0; } } } //新增邊(無向圖) public void addEdge(int i,int j){ //邊的頭尾不能為同一個節點 if(i==j)return; arcs[i][j]=1; arcs[j][i]=1; } //設定節點集 public void setVertices(char[] vertices){ this.vertices=vertices; } //設定節點訪問標記 public void setVisited(boolean[] visited){ this.visited=visited; } //列印遍歷節點 public void visit(int i){ System.out.print(vertices[i]+" "); } //非遞迴方法是實現深度優先遍歷 public void DFSTraverse(){ //初始化節點遍歷標記 for(int i=0;i<vexnum;i++){ visited[i]=false; } //建立一個棧 Stack<Integer> s=new Stack<Integer>(); //對非聯通圖執行迴圈進行遍歷以至於所有節點都遍歷到 //若是連通圖該for迴圈只執行一次 for(int i=0;i<vexnum;i++){ if(!visited[i]){ //連通子圖起始節點 s.add(i); do{ //出棧 int curr=s.pop(); //如果節點還沒有被遍歷到,則遍歷該節點並將該節點入棧用來遍歷其子節點 if(visited[curr]==false){ //遍歷並列印 visit(curr); visited[curr]=true; //沒遍歷的子節點入棧 for(int j=vexnum-1;j>=0;j--){ if(arcs[curr][j]==1&&visited[j]==false){ s.add(j); } } } }while(!s.isEmpty()); } } } //從第i個節點開始深度優先遍歷 private void traverse(int i){ //標記第i個節點已被遍歷 visited[i]=true; //列印當前遍歷的節點 visit(i); //遍歷鄰接矩陣中第i個節點的直接連通關係 for(int j=0;j<vexnum;j++){ //目標節點與當前節點直接連通並沒有被訪問,遞迴遍歷 if(arcs[i][j]==1&&visited[j]==false){ traverse(j); } } } //圖的深度優先遍歷(遞迴法) public void DFSTraverse1(){ //初始化節點遍歷標記 for(int i=0;i<vexnum;i++){ visited[i]=false; } //從沒有被遍歷的節點開始深度遍歷 //連通圖的話這個迴圈只會執行一次 for(int i=0;i<vexnum;i++){ if(visited[i]==false) traverse(i); } } }
package SevenProvience.tital2;
public class test {
public static void main(String[] args) {
DFS g = new DFS(9);
char[] vertices = {'A','B','C','D','E','F','G','H','I'};
g.setVertices(vertices);
g.addEdge(0, 1);
g.addEdge(0, 5);
g.addEdge(1, 0);
g.addEdge(1, 2);
g.addEdge(1, 6);
g.addEdge(1, 8);
g.addEdge(2, 1);
g.addEdge(2, 3);
g.addEdge(2, 8);
g.addEdge(3, 2);
g.addEdge(3, 4);
g.addEdge(3, 6);
g.addEdge(3, 7);
g.addEdge(3, 8);
g.addEdge(4, 3);
g.addEdge(4, 5);
g.addEdge(4, 7);
g.addEdge(5, 0);
g.addEdge(5, 4);
g.addEdge(5, 6);
g.addEdge(6, 1);
g.addEdge(6, 3);
g.addEdge(6, 5);
g.addEdge(6, 7);
g.addEdge(7, 3);
g.addEdge(7, 4);
g.addEdge(7, 6);
g.addEdge(8, 1);
g.addEdge(8, 2);
g.addEdge(8, 3);
System.out.println("深度優先遍歷(非遞迴):");
g.DFSTraverse();
System.out.println();
System.out.println("深度優先遍歷(遞迴):");
g.DFSTraverse1();
}
}