原文地址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); } } }