图论(六)图的深度优先遍历DFS(非递归方式)

开发者 2024-9-28 07:51:27 110 0 来自 中国
一、深度优先搜索

深度优先搜索是一个针对图和树的遍历算法。早在19世纪就被用于解决迷宫标题。
对于下面的树而言,DFS方法起首从根节点1开始,其搜索节点序次是1,2,3,4,5,6,7,8(假定左分枝和右分枝中优先选择左分枝)。
DFS的非递归实现方式相比于BFS应该说大同小异,只是把queue换成了stack而已,stack具有后进先出LIFO(Last Input First Output)的特性,DFS的操纵步调如下:

  • 1、把起始点放入stack;
  • 2、重复下述3步调,直到stack为空为止:

    • 从stack中访问栈顶的点;
    • 找出与此点毗连的且尚未遍历的点,举行标志,然后全部放入stack中;
    • 假云云点没有尚未遍历的毗连点,则将此点从stack中弹出。

二、深度优先遍历(非递归)图文演示

下面团结一个图(graph)的实例,分析DFS的工作过程和原理:

  • 1、将起始节点1放入栈stack中,标志为已遍历。
2.png

  • 2、从stack中访问栈顶的节点1,找出与节点1毗连的节点,有2、9两个节点,我们可以选择此中任何一个,选择规则可以人为设定,这里假设按照节点数字序次由小到大选择,选中的是2,标志为已遍历,然后放入stack中。
3.png

  • 3、从stack中取出栈顶的节点2,找出与节点2毗连的节点,有1、3、5三个节点,节点1已遍历过,清除;3、5中按照预定的规则选中的是3,标志为已遍历,然后放入stack中。


  • 4、从stack中取出栈顶的节点3,找出与节点3毗连的节点,有2、4两个节点,节点2已遍历过,清除;选中的是节点4,标志为已遍历,然后放入stack中。


  • 5、从stack中取出栈顶的节点4,找出与节点4毗连的节点,有3、5、6三个节点,节点3已遍历过,清除;选中的是节点5,标志为已遍历,然后放入stack中。
6.png

  • 6、从stack中取出栈顶的节点5,找出与节点5毗连的节点,有2、4两个节点,节点2、4都已遍历过,因此节点5没有尚未遍历的毗连点,则将此点从stack中弹出。


  • 7、当前stack栈顶的节点是4,找出与节点4毗连的节点,有3、5、6三个节点,节点3、5都已遍历过,清除;选中的是节点6,标志为已遍历,然后放入stack中。


  • 8、当前stack栈顶的节点是6,找出与节点6毗连的节点,有4、7、8三个节点,4已遍历,按照规则选中的是7,标志为已遍历,然后放入stack中。
9.png

  • 9、当前stack栈顶的节点是7,找出与节点7毗连的节点,只有节点6,已遍历过,因此没有尚未遍历的毗连点,将节点7从stack中弹出。


  • 10、当前stack栈顶的节点是6,找出与节点6毗连的节点,有节点7、8,7已遍历过,因此将节点8放入stack中。
11.png

  • 11、当前stack栈顶的节点是8,找出与节点8毗连的节点,有节点1、6、9,1、6已遍历过,因此将节点9放入stack中。


  • 12、当前stack栈顶的节点是9,没有尚未遍历的毗连点,将节点9弹出,依次类推,栈中剩余节点8、6、4、3、2、1都没有尚未遍历的毗连点,都将弹出,末了栈为空。
  • 13、DFS遍历完成。
三、毗连表举行深度优先遍历

3.1 构建数据布局

public class Graph {    //顶点个数    private int V;    //边的条数    private int E;    //领接表的底层存储布局    private TreeSet<Integer>[] adj;}3.2 通过该布局界说,构造一个图(无向图)

/** * @Author: huangyibo * @Date: 2022/3/28 1:02 * @Description: 领接表, 现在只支持无向无权图 */public class Graph {    //顶点个数    private int V;    //边的条数    private int E;    //领接表的底层存储布局    private TreeSet<Integer>[] adj;    public Graph(String filename){        File file = new File(filename);        try {            Scanner scanner = new Scanner(file);            V = scanner.nextInt();            if(V < 0){                throw new IllegalArgumentException("V must be non-negative");            }            adj = new TreeSet[V];            //初始化领接表            for (int i = 0; i < V; i++) {                adj = new TreeSet<>();            }            E = scanner.nextInt();            if(E < 0){                throw new IllegalArgumentException("E must be non-negative");            }            for (int i = 0; i < E; i++) {                int a = scanner.nextInt();                //校验顶点a是否合法                validateVertex(a);                int b = scanner.nextInt();                //校验顶点b是否合法                validateVertex(b);                //校验是否是自环边                if(a == b){                    throw new IllegalArgumentException("Self Loop is Detected!");                }                //校验是否是平行边                if(adj[a].contains(b)){                    throw new IllegalArgumentException("arallel Edges are Detected!");                }                adj[a].add(b);                adj.add(a);            }        } catch (FileNotFoundException e) {            e.printStackTrace();        }    }    /**     * 校验顶点是否合法     * @param v     */    private void validateVertex(int v){        if(v < 0 || v >= V){            throw new IllegalArgumentException("vertex " + v + " is invalid");        }    }    /**     * 获取顶点个数     * @return     */    public int V(){        return V;    }    /**     * 获取边的条数     * @return     */    public int E(){        return E;    }    /**     * 图中是否存在v到w的边     * @param v     * @param w     * @return     */    public boolean hasEdge(int v, int w){        //校验顶点v是否合法        validateVertex(v);        //校验顶点w是否合法        validateVertex(w);        return adj[v].contains(w);    }    /**     * 返回和v相邻的顶点     * @param v     * @return     */    public Iterable<Integer> adj(int v){        //校验顶点v是否合法        validateVertex(v);        return adj[v];    }    /**     * 返回顶点v的度     * 顶点v的度(Degree)是指在图中与v干系联的边的条数     * @param v     * @return     */    public int degree(int v){        //校验顶点v是否合法        validateVertex(v);        return adj[v].size();    }    @Override    public String toString() {        StringBuilder sb = new StringBuilder();        sb.append(String.format("V = %d, E = %d\n", V, E));        for (int v = 0; v < V; v++) {            sb.append(String.format("%d : ", v));            for (Integer w : adj[v]) {                sb.append(String.format("%d ", w));            }            sb.append("\n");        }        return sb.toString();    }}3.3 毗连表的深度优先算法(非递归)

/** * @Author: huangyibo * @Date: 2022/3/28 1:02 * @Description: 图的深度优先遍历, 非递归方式 */public class GraphDFS {    private Graph G;    /**     * 图的顶点是否已经被遍历过     */    private boolean[] visited;    //图的深度优先遍历效果    private List<Integer> order = new ArrayList<>();    public GraphDFS(Graph G){        this.G = G;        visited = new boolean[G.V()];        //循环全部顶点, 防止一个图出现多个连通图(连通分量)的情况        for (int v = 0; v < G.V(); v++) {            if(!visited[v]){                dfs(v);            }        }    }    /**     * 图的深度优先遍历, 非递归方式     * @param source     */    private void dfs(int source) {        Stack<Integer> stack = new Stack<>();        //将源结点压入栈顶        stack.push(source);        //标志为已访问        visited[source] = true;        //假如栈不为空        while(!stack.isEmpty()){            Integer v = stack.pop();            //当前出栈顶点添加到图的深度优先遍历效果集            order.add(v);            //遍历顶点V的相邻顶点            for (Integer w : G.adj((v))) {                //假如没有遍历过                if(!visited[w]){                    //顶点w压入栈顶                    stack.push(w);                    //标志w为已访问                    visited[w] = true;                }            }        }    }    /**     * 图的深度优先遍历效果集     * @return     */    public List<Integer> order(){        return order;    }    public static void main(String[] args) {        Graph graph = new Graph("src/main/resources/g1.txt");        GraphDFS graphDFS = new GraphDFS(graph);        System.out.println(graphDFS.order());    }}g1.txt

7 60 10 21 31 42 32 6参考:
https://blog.csdn.net/saltriver/article/details/54429068
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-11-24 21:09, Processed in 0.185961 second(s), 35 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表