图的遍历(DFS和BFS)

图的遍历是指从图中某一顶点出发,访遍图中其余顶点,且使每一个顶点仅被访问一次。

一、深度优先遍历(Depth First Search)

假设给定图G的初态是所有顶点均未曾访问过。在G中任选一顶点v为初始出发点(源点),则深度优先遍历可定义如下:首先访问出发点v,并将其标记为已访问过;然后依次从v出发搜索v的每个邻接点w。若w未曾访问过,则以w为新的出发点继续进行深度优先遍历,直至图中所有和源点v有路径相通的顶点(亦称为从源点可达的顶点)均已被访问为止。若此时图中仍有未访问的顶点,则另选一个尚未访问的顶点作为新的源点重复上述过程,直至图中所有顶点均已被访问为止。

深度优先遍历是一个递归的过程,类似于树的前序遍历,它的策略是尽可能的对纵深方向进行搜索。

有向网图邻接矩阵DPS代码示例:

    //邻接矩阵DFS算法
    private static void DFS(AdjacencyMatrix.Matrix matrix, int i){
        int j;
        visited[i] = true;
        System.out.print(matrix.getVexs()[i]);
        for (j = 0; j < matrix.getVerNum(); j++){
            if(matrix.getArc()[i][j] > 0 && ! visited[j]&&matrix.getArc()[i][j] != 65535 )
                DFS(matrix, j);
        }
    }
    //邻接矩阵深度遍历操作
    private static void DFSTraverse(){

        adjacencyMatrix.CreateMGraph();
        mGraph = adjacencyMatrix.matrix;     //图的矩阵表示
        int i;
        for (i = 0; i < mGraph.getVerNum(); i++){
            visited[i] = false;              //是否访问的标志
        }

        for(i = 0; i < mGraph.getVerNum(); i++){
            if(! visited[i]){
                DFS(mGraph, i);
            }
        }
    }

有向网图邻接表DFS代码示例:

    //邻接表DFS算法
    private static void DFS(AdjacencyList.AdjacencyGraph graph, int i){
        AdjacencyList.EdgeNode edgeNode;
        visited[i] = true;
        System.out.print(graph.getVertexNodes()[i].getData());
        edgeNode = graph.getVertexNodes()[i].getFirstEdge();
        while (edgeNode != null){
            if(!visited[edgeNode.getAdjvex()]){
                DFS(graph, edgeNode.getAdjvex());
            }

            edgeNode = edgeNode.getNext();
        }
    }
    //邻接表深度遍历操作
    private static void DFSTraverse(){

        adjacencyList.CreateList();
        lGraph = adjacencyList.adjacencyGraph;
        int i;
        for(i = 0; i < lGraph.getVertexNum(); i++)
            visited[i] = false;

        for (i = 0; i < lGraph.getVertexNum(); i++){
            if(! visited[i]){
                DFS(lGraph, i);
            }
        }
    }

对比两种存储结构的DFS算法,邻接矩阵是二维数组,时间复杂度为O(n^2^),邻接表的时间复杂度为O(n+e),e为边数,当点多边少时,邻接表更优。

广度优先遍历(Breadth First Search)

1、从图中某个顶点V0出发,并访问此顶点;
2、从V0出发,访问V0的各个未曾访问的邻接点W1,W2,…,Wk;然后,依次从W1,W2,…,Wk出发访问各自未被访问的邻接点;
3、重复步骤2,直到全部顶点都被访问为止。

广度优先遍历类似于树的层序遍历。树的层序遍历是通过队列实现的,图也同理。

邻接矩阵DFS算法:

    //邻接矩阵BFS算法
    private static void BFSTraverse(){

        int i,j;
        Queue<Integer> queue = new LinkedList<>();
        for(i = 0; i < mGraph.getVerNum(); i++)
            visited[i] = false;

        for (i = 0; i < mGraph.getVerNum(); i++){
            if(! visited[i]){
                visited[i] = true;
                System.out.print(mGraph.getVexs()[i]);
                queue.add(i);
                while (! queue.isEmpty()){
                    queue.poll();
                    for (j = 0; j < mGraph.getVerNum(); j++){
                        if(mGraph.getArc()[i][j] > 0 && ! visited[j] && mGraph.getArc()[i][j] != 65535){
                            visited[j] = true;
                            System.out.print(mGraph.getVexs()[j]);
                            queue.poll();
                        }
                    }
                }
            }
        }
    }

邻接表DFS算法:

    //邻接表BFS算法
    private static void BFSTraverse(){
        int i;
        AdjacencyList.EdgeNode edgeNode;
        Queue<Integer> queue = new LinkedList<>();

        for(i = 0; i < lGraph.getVertexNum(); i++){
            visited[i] = false;
        }

        for (i = 0; i < lGraph.getVertexNum(); i++){
            if(! visited[i]){
                visited[i] = true;
                System.out.print(lGraph.getVertexNodes()[i].getData());
                queue.add(i);
                while (! queue.isEmpty()){
                    queue.poll();
                    edgeNode = lGraph.getVertexNodes()[i].getFirstEdge();
                    while (edgeNode != null) {
                        if(! visited[edgeNode.getAdjvex()]) {
                            visited[edgeNode.getAdjvex()] = true;
                            System.out.print(lGraph.getVertexNodes()[edgeNode.getAdjvex()].getData());
                            queue.poll();
                        }
                        edgeNode = edgeNode.getNext();
                    }
                }
            }
        }
    }

深度优先适合目标比较明确,以找到目标为主要目的情况,广度优先更适合在不断扩大遍历范围时找到相对最优解的情况。

本文用到的代码链接

    原文作者:数据结构之图
    原文地址: https://blog.csdn.net/biangu1486/article/details/81485676
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞