深度优先搜索最初是因为迷宫游戏而诞生的。在一个迷宫中,有一个入口和一个出口,其中只有一条路径能从入口到达出口。在走迷宫的时候,每次将走过的地方进行标记,遇到死胡同的时候可以沿着进来的路线后退,找到新的没走过的拐角再尝试新的路线。这种方法的效率很高,因为每个地方只需要走过一次即可。其实,这就是深度优先搜索。
深度优先搜索的目标就是系统化地遍历整个图,让算法的效率更高。
应用
深度优先搜索有几个非常典型的应用:
- 找出源顶点能到达的所有顶点
- 找出两个顶点之间的路径
- 判断两个顶点是否连通
基本思想
深度优先搜索的步骤如下:
- 将v标记为已拜访
- 迭代拜访与v相邻的没有拜访过的所有顶点
设计模式
和图论有关的算法非常多,相应的数据结构也非常多。那么,为了不让Graph这个类变得太复杂,所以需要将图论的算法放在另外一个单独的对象中,这样两个类之间的耦合度低一些,编码的时候也会更加好用。因此在后续的章节中都会采用这样的设计模式,使得每个算法都会有一个单独的类。
代码
import java.util.Stack; /** * Created by caipeichao on 14-6-10. */ public class DFS { private boolean[] visited; private int[] edgeTo; private int s; /** * @param G 图 * @param s 遍历的起点 */ public DFS(Graph G, int s) { this.s = s; // 所有的顶点都没有访问过 visited = new boolean[G.V()]; // 从哪个顶点来的? edgeTo = new int[G.V()]; // 开始深搜 dfs(G, s); } private void dfs(Graph G, int v) { visited[v] = true; for (int w : G.adj(v)) { if (!visited[w]) { edgeTo[w] = v; dfs(G, w); } } } public boolean hasPathTo(int v) { return visited[v]; } public Iterable<Integer> pathTo(int v) { if(!hasPathTo(v)) return null; // 注意:这句话不要忘记了 Stack<Integer> result = new Stack<Integer>(); while (v != s) { // 注意:到达源点的时候就应该退出循环 result.add(v); v = edgeTo[v]; } return result; } }
复杂度
简单地说复杂度和参与运算的边数成正比。所谓参与运算的边就是指源点能到达的边。
时间: 2024-10-25 22:36:43