图的深度优先遍历的概念与实现

图的深度优先遍历是从初始顶点出发,找到是否有邻接点,判断是否访问过,如果没有访问过访问该邻接点,如果邻接点还有邻接点就继续访问,直到到达没有邻接点可以访问的顶点,就回退到上一个顶点。
深度优先遍历可以想象成走迷宫,一直路过各个顶点,直到没有路了,再回退到上个顶点继续走。因此是递归思想。可以用方法(method)递归和栈(stack)递归两种方式实现。

接口Paths是抽象出遍历路径的类。

public class DepthFirstSearch implements Paths{
    //标记是否被访问列表
    private boolean[] marked;
    //访问的次数
    private int count;

    private int[] edgeTo;//源顶点,用来记录寻找路径

    private int start;
    /** * * @param graph 图对象 * @param start 开始的节点 */
    public DepthFirstSearch(UndirectedGraph graph,int start){
        //通过顶点数创建访问列表
        marked = new boolean[graph.vertexNum()];
        this.start = start;
        edgeTo = new int[graph.vertexNum()];
        dfsForStack(graph, start);
    }
    /** * 深度遍历图方法,递归 * @param graph 图对象 * @param vertex 顶点下标 */
    private void dfs(UndirectedGraph graph,int vertex){
        //将顶点标记为已经被访问
        marked[vertex] = true;
        //访问顶点
        System.out.println(vertex);
        count++;
        //获取顶点邻接的顶点
        Iterable<Integer> adj = graph.adj(vertex);
        //访问邻接的顶点
        for (Integer integer : adj) {
            //如果顶点没有被访问过,就递归的访问
            if(!marked[integer]){
                //记录顶点被访问的源路径,因为每个顶点的源被访问一次,所以只会有一个源路径
                edgeTo[integer] = vertex;
                dfs(graph,integer);
            }
        }
    }
    /** * 非递归,栈实现 * @param graph * @param vertex */
    private void dfsForStack(UndirectedGraph graph,int vertex){
        Stack<Integer> stack = new Stack<>();
        stack.push(vertex);
        while(!stack.isEmpty()){
            vertex = stack.peek();
            //如果没被访问过,就访问
            if(!marked[vertex]){
                marked[vertex] = true;
                System.out.println(vertex);
                //然后再继续访邻接顶点
                Iterable<Integer> adj = graph.adj(vertex);
                for (Integer integer : adj) {
                    //访问没有被访问的邻接顶点
                    if(!marked[integer]){
                        //将邻接顶点入栈,如果栈中存在,就置顶
                        if(stack.contains(integer)){
                            //移除然后在添加就置顶了
                            stack.removeElement(integer);
                        }
                        //记录顶点的源顶点
                        edgeTo[integer] = vertex;
                        stack.push(integer);

                    }
                }
            }else{
                //访问过就弹出
                stack.pop();
            }
        }
    }
    /** * 是否包含到v的路径 */
    @Override
    public boolean hasPathTo(int v) {
        //该顶点是否被访问过
        return marked[v];
    }
    /** * 找到起始顶点到指定顶点(v)的一条路径 */
    @Override
    public Iterable<Integer> pathTo(int v) {
        if(!hasPathTo(v)){
            return null;
        }
        Stack<Integer> path = new Stack<>();
        //从路径的顶点,递归回到开始的节点
        for(int m = v;m != start ;m = edgeTo[m]){
            path.push(m);
        }
        path.push(start);
        return path;
    }

}

paths接口

/** * 路径接口 * @author yuli * */
public interface Paths {
    /** * 是否包含到v的路径 * @param v * @return */
    boolean hasPathTo(int v);
    /** * 返回到v经过的路径 * @param v * @return */
    Iterable<Integer> pathTo(int v);
}
    原文作者:数据结构之图
    原文地址: https://blog.csdn.net/yulio1234/article/details/77731575
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞