图的深度优先遍历(Depth First Search)

图的深度优先遍历(Depth First Search)

基本思想

类似于二叉树的先序遍历

  1. 假设图中所有结点均未被访问,从初始结点访问,访问其第一个邻接结点,接着以被访问的邻接结点作为初始结点,访问它的第一个邻接结点。

  2. 递归的过程。

算法步骤

  1. 访问初始结点v,并标记为已访问

  2. 查找结点v的第一个邻接结点w

  3. 若w存在,则继续执行4,若不存在则回到第1步,从v的下一个结点继续

  4. 若w未被访问,对w进行深度优先遍历递归(即把w当做另一个v,然后进行步骤123)

  5. 查找结点v的邻接结点w的下一个邻接结点,转到步骤3

无向图深度优先遍历演示

1. 访问A

2. 访问(A的邻接点)C
   在第1步访问A之后,接下来应该访问的是A的邻接点,即"C,D,F"中的一个。但在本文的实现中,顶点ABCDEFG是按照顺序存储,C在"D和F"的前面,因此,先访问C。

3. 访问(C的邻接点)B
   在第2步访问C之后,接下来应该访问C的邻接点,即"B和D"中一个(A已经被访问过,就不算在内)。而由于B在D之前,先访问B。

4. 访问(C的邻接点)D
   在第3步访问了C的邻接点B之后,B没有未被访问的邻接点;因此,返回到访问C的另一个邻接点D。

5. 访问(A的邻接点)F
   前面已经访问了A,并且访问完了"A的邻接点C的所有邻接点(包括递归的邻接点在内)";因此,此时返回到访问A的另一个邻接点F。

6. 访问(F的邻接点)G

7. 访问(G的邻接点)E

   因此访问顺序是:A -> C -> B -> D -> F -> G -> E

有向图深度优先遍历演示

1. 访问A

2. 访问B
   在访问了A之后,接下来应该访问的是A的出边的另一个顶点,即顶点B。

3. 访问C
   在访问了B之后,接下来应该访问的是B的出边的另一个顶点,即顶点C,E,F。在本文实现的图中,顶点ABCDEFG按照顺序存储,因此先访问C。

4. 访问E
   接下来访问C的出边的另一个顶点,即顶点E。

5. 访问D
   接下来访问E的出边的另一个顶点,即顶点B,D。顶点B已经被访问过,因此访问顶点D。

6. 访问F
   访问D之后,出边顶点C已访问;回溯到E,E的出边顶点BD均访问;依次回溯到B,B的出边顶点CF中F未访问,所以访问F。

7. 访问G

   因此访问顺序是:A -> B -> C -> E -> D -> F -> G

算法实现

import java.util.ArrayList;
import java.util.Arrays;

public class GraphTraversal {
    private ArrayList<Object> nodeList;//存储结点的集合
    private int[][] edges;//结点与结点之间的连线关系
    private int numOfEdges;//图中连线数量
    private boolean[] isVisited;//标记结点是否被访问


    public GraphTraversal(int n){
        //初始化矩阵和顶点列表
        nodeList = new ArrayList<Object>(n);
        edges = new int[n][n];
        numOfEdges = 0;
        isVisited = new boolean[n];

    }

    public static void main(String[] args) {
        //声明图中结点
        int n = 7;
        String nodes[] = {"A","B","C","D","E","F","G"};
        //创建一个无向图
        GraphTraversal undirectedGraph = new GraphTraversal(n);
        //将顶点添加到图中
        if(undirectedGraph.addNodes(nodes) > 0){
            //添加顶点间的关系
            undirectedGraph.insertUndirectedEdge(0, 3, 1);
            undirectedGraph.insertUndirectedEdge(0, 2, 1);
            undirectedGraph.insertUndirectedEdge(0, 5, 1);
            undirectedGraph.insertUndirectedEdge(2, 1, 1);
            undirectedGraph.insertUndirectedEdge(2, 3, 1);
            undirectedGraph.insertUndirectedEdge(5, 6, 1);
            undirectedGraph.insertUndirectedEdge(6, 4, 1);

            //显示邻接矩阵
            System.out.println("无向图邻接矩阵:");
            undirectedGraph.showGraph();

            //无向图深度优先遍历
            System.out.println("无向图深度优先遍历:");
            undirectedGraph.dfs();
        }



        //创建一个有向图
        GraphTraversal directedGraph = new GraphTraversal(n);
        //添加结点到图中
        if (directedGraph.addNodes(nodes) > 0){
            //添加结点之间的关系
            directedGraph.insertDirectedEdge(0,1,1);
            directedGraph.insertDirectedEdge(1,2,1);
            directedGraph.insertDirectedEdge(1,4,1);
            directedGraph.insertDirectedEdge(1,5,1);
            directedGraph.insertDirectedEdge(2,4,1);
            directedGraph.insertDirectedEdge(3,2,1);
            directedGraph.insertDirectedEdge(4,3,1);
            directedGraph.insertDirectedEdge(4,1,1);
            directedGraph.insertDirectedEdge(5,6,1);

            //显示邻接矩阵
            System.out.println("有向图邻接矩阵:");
            directedGraph.showGraph();

            //有向图深度优先遍历
            System.out.println("有向图深度优先遍历:");
            directedGraph.dfs();

        }
    }

    //将结点添加到图中
    public int addNodes(Object[] nodes){
        for (Object node : nodes){
            nodeList.add(node);
        }
        return nodeList.size();
    }

    //创建无向图结点关系
    public void insertUndirectedEdge(int v1, int v2, int weight){
        edges[v1][v2] = weight;
        edges[v2][v1] = weight;
        numOfEdges++;
    }

    //创建有向图结点关系
    public void insertDirectedEdge(int v1, int v2, int weight){
        edges[v1][v2] = weight;
        numOfEdges++;
    }

    //显示邻接矩阵
    public void showGraph(){
        for (int[] link : edges){
            System.out.println(Arrays.toString(link));
        }
    }

    //根据初始结点获取第一个邻接结点
    public int getFirstNeighbor(int v1){
        for(int v2 = 0; v2 < edges.length; v2++){
            if (edges[v1][v2] > 0){
                return v2;
            }
        }
        return -1;
    }

    //根据前一个邻接结点获取下一个邻接结点
    public int getNextNeighbor(int v1, int v2){
        for (int j = v2 + 1; j < edges.length; j++){//从上一个结点[v1]开始找下一个结点
            if (edges[v1][j] > 0){//若 v1 到 j 的连线存在,则存在下一个结点
                return j;
            }
        }
        return -1;//说明不存在下一个结点
    }

    //dfs深度优先遍历
    public void dfs(boolean[] isVisited, int v){
        //输出当前访问的起始结点
        System.out.print(nodeList.get(v) + "->");//根据索引值获取List中结点值

        //当前起始结点标记为已访问
        isVisited[v] = true;

        //访问起始结点的第一个邻接结点
        int w = getFirstNeighbor(v);
        while (w != -1){//说明存在第一个邻接结点
            if (!isVisited[w]){//未被标记为已访问
                dfs(isVisited, w);//把当前的邻接结点作为起始结点,递归执行深度遍历算法
            }
            //如果w结点已经被访问,则寻找下一个邻接结点
            w = getNextNeighbor(v, w);
        }
    }

    //对 dfs 重载,使其对所有结点进行 dfs
    public void dfs(){
        for (int i = 0; i < nodeList.size(); i++){
            if (!isVisited[i]){//结点未被标记为已访问
                dfs(isVisited, i);//第 i 个结点作为初始结点进行 dfs
            }
        }
        System.out.println();
    }
}
  • 4
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值