原文地址java
public class Graph { // 頂點的個數 private int v; // 每一個頂點後面有個鏈表 private LinkedList<Integer>[] adj; public Graph(int v) { this.v = v; adj = new LinkedList[v]; for (int i = 0; i < v; i++) { adj[i] = new LinkedList<>(); } } /** * 添加邊 * @param s 頂點 * @param t 頂點 */ public void addEdge(int s,int t){ // 無向圖一條邊存兩次(聯想微信好友) adj[s].add(t); adj[t].add(s); } }
/** * 圖的廣度優先搜索,搜索一條從 s 到 t 的路徑。 * 這樣求得的路徑就是從 s 到 t 的最短路徑。 * * @param s 起始頂點 * @param t 終止頂點 */ public void bfs(int s, int t) { if (s == t) { return; } // visited 記錄已經被訪問的頂點,避免頂點被重複訪問。若是頂點 q 被訪問,那相應的visited[q]會被設置爲true。 boolean[] visited = new boolean[v]; visited[s] = true; // queue 是一個隊列,用來存儲已經被訪問、但相連的頂點尚未被訪問的頂點。由於廣度優先搜索是逐層訪問的,只有把第k層的頂點都訪問完成以後,才能訪問第k+1層的頂點。 // 當訪問到第k層的頂點的時候,須要把第k層的頂點記錄下來,稍後才能經過第k層的頂點來找第k+1層的頂點。 // 因此,用這個隊列來實現記錄的功能。 Queue<Integer> queue = new LinkedList<>(); queue.add(s); // prev 用來記錄搜索路徑。當從頂點s開始,廣度優先搜索到頂點t後,prev數組中存儲的就是搜索的路徑。 // 不過,這個路徑是反向存儲的。prev[w]存儲的是,頂點w是從哪一個前驅頂點遍歷過來的。 // 好比,經過頂點2的鄰接表訪問到頂點3,那prev[3]就等於2。爲了正向打印出路徑,須要遞歸地來打印,就是print()函數的實現方式。 int[] prev = Arrays.stream(new int[v]).map(f -> -1).toArray(); while (queue.size() != 0) { int w = queue.poll(); LinkedList<Integer> wLinked = adj[w]; // 表示:鄰接表存儲時頂點爲w,所對應的鏈表 for (int i = 0; i < wLinked.size(); ++i) { int q = wLinked.get(i); // 判斷頂點 q 是否被訪問 if (!visited[q]) { // 未被訪問 prev[q] = w; if (q == t) { print(prev, s, t); return; } visited[q] = true; queue.add(q); } } } } // 遞歸打印s->t的路徑 private void print(int[] prev, int s, int t) { if (prev[t] != -1 && t != s) { print(prev, s, prev[t]); } System.out.print(t + " "); }
原理以下:git
// 全局變量或者類成員變量,標記是否找到終點 t boolean found = false; /** * 深度優先搜索 * * @param s 起始頂點 * @param t 終止頂點 */ public void dfs(int s, int t) { found = false; // 標記頂點是否被訪問 boolean[] visited = new boolean[v]; // prev 用來記錄搜索路徑,prev[w] = a 表示 w 頂點的上一級節點爲 a int[] prev = Arrays.stream(new int[v]) .map(f -> -1).toArray(); recurDfs(s, t, visited, prev); print(prev, s, t); } private void recurDfs(int w, int t, boolean[] visited, int[] prev) { if (found == true) { return; } visited[w] = true; if (w == t) { found = true; return; } LinkedList<Integer> wLinked = adj[w]; for (int i = 0; i < wLinked.size(); ++i) { int q = wLinked.get(i); if (!visited[q]) { prev[q] = w; recurDfs(q, t, visited, prev); } } }