首页 > 代码库 > 算法7-3:深度优先搜索

算法7-3:深度优先搜索

深度优先搜索最初是因为迷宫游戏而诞生的。在一个迷宫中,有一个入口和一个出口,其中只有一条路径能从入口到达出口。在走迷宫的时候,每次将走过的地方进行标记,遇到死胡同的时候可以沿着进来的路线后退,找到新的没走过的拐角再尝试新的路线。这种方法的效率很高,因为每个地方只需要走过一次即可。其实,这就是深度优先搜索。


深度优先搜索的目标就是系统化地遍历整个图,让算法的效率更高。


应用


深度优先搜索有几个非常典型的应用:

  • 找出源顶点能到达的所有顶点

  • 找出两个顶点之间的路径

  • 判断两个顶点是否连通


基本思想


深度优先搜索的步骤如下:

  1. 将v标记为已拜访

  2. 迭代拜访与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;
    }
}


复杂度


简单地说复杂度和参与运算的边数成正比。所谓参与运算的边就是指源点能到达的边。