zoukankan      html  css  js  c++  java
  • 图的优先遍历:广度优先搜索和深度优先搜索

      广度优先搜索,该算法是将已发现结点和未发现结点之间的边界,沿着其广度方向向外扩展,算法需要发现所有距离源结点 s k所有结点之后,才会发现距离源结点 s 为 k+1其他结点。如果结点都被访问,算法终止。

      此过程需要先构建一颗广度优先树。一开始,该树只有根结点 s (源节点)。在扫描已发现结点 s 的邻接表时,每发现一个白色结点 v,就把结点染黑(这是为了记录访问的痕迹),并把它们之间的边(u, v)加入广度优先树。

      该算法使用了一个具有 FIFO 特性的队列来管理已知未知两个集合之间的边界。其中,一个数组记录结点的信息,一个存储结点之间边的关系的数组,还有一个数组来记录结点的访问痕迹

      广度优先搜索算法:

     1     /**
     2      * 广度优先遍历
     3      */
     4     public void BFS() {
     5         Queue<Integer> queue = new LinkedList<>();
     6         // 遍历每个顶点
     7         for (int i = 0; i < vertexSize; i++) {
     8             if (!visited[i]) {
     9                 queue.add(i); // 当前节点入队
    10                 visited[i] = true;
    11                 System.out.print(vertexesArray[i] + " ");
    12 
    13                 // 队列不为空时
    14                 while (!queue.isEmpty()) {
    15                     // 移除当前队列队首的顶点
    16                     int row = queue.remove();
    17 
    18                     // 遍历当前队首的顶点能指向的所有节点(距离为1)
    19                     for (int k = firstAdjVex(row); k >= 0; k = nextAdjVex(row, k)) {
    20                         if (!visited[k]) {
    21                             queue.add(k);
    22                             visited[k] = true;
    23                             System.out.print(vertexesArray[k] + " ");
    24                         }
    25                     }
    26                 }
    27             }
    28         }
    29     }

      寻找当前结点能指向的节点:

     1     /**
     2      * 能指向的第一个节点
     3      * @param row 当前节点
     4      * @return 当前节点能指向的第一个节点位置,不存在返回-1
     5      */
     6     private int firstAdjVex(int row) {
     7         for (int column = 0; column < vertexSize; column++) {
     8             if (edgesMatrix[row][column] == 1)
     9                 return column;
    10         }
    11         return -1;
    12     }
    13 
    14     /**
    15      * 接下来指向的下一个节点
    16      * @param row 当前节点
    17      * @param k   从顶点表的k位置,找当前节点能指向的结点(k位置之后的结点,k及k之前得到找过了一遍)
    18      * @return 下一个节点位置,不存在返回-1
    19      */
    20     private int nextAdjVex(int row, int k) {
    21         for (int j = k + 1; j < vertexSize; j++) {
    22             if (edgesMatrix[row][j] == 1)
    23                 return j;
    24         }
    25         return -1;
    26     }

      分析:队列入队出队时间复杂度为O(1),所以队列总的操作时间为O(V);在队列中的结点出队的时候才回去扫描这个结点的邻接表,每个邻接表只扫描一次,总的时间为O(E)。因此总的运行时间为O(V+E)。

      深度优先搜索,总是对最近发现的结点 v 的出发边进行探索,直到该结点的所有出发边都被发现为止。一但所有出发边都被发现,搜索则“回溯”到 v 的前驱结点(v 是经过结点才被发现的),来搜索改前去结点的出发边。

     1     public void DFS(Object o) {
     2         int index = -1;
     3         // 遍历所有节点中是否存在目的地
     4         for (int i = 0; i < vertexSize; i++) {
     5             if (vertexesArray[i].equals(o)) {
     6                 index = i;
     7                 break;
     8             }
     9         }
    10 
    11         if (index == -1) {
    12             new NullPointerException("不存该值" + o);
    13         }
    14 
    15         // 初始化所有节点的访问痕迹
    16         for (int i = 0; i < vertexSize; i++) {
    17             visited[i] = false;
    18         }
    19 
    20         traverse(index);// 有向图
    21 
    22         // 无向图,依次将每个顶点遍历能抵达的所有边
    23         if (graphType) {
    24             for (int i = 0; i < vertexSize; i++) {
    25                 if (!visited[i])
    26                     traverse(i);
    27             }
    28         }
    29     }
    30 
    31     /**
    32      * 深度优先就是由开始点向最深处遍历,没有了就回溯到上一级顶点
    33      * @param i 当前顶点
    34      */
    35     private void traverse(int i) {
    36         visited[i] = true;
    37         System.out.print(vertexesArray[i] + " ");
    38 
    39         for (int j = firstAdjVex(i); j >= 0; j = nextAdjVex(i, j)) {
    40             if (!visited[j]) {
    41                 traverse(j);
    42             }
    43         }
    44     }

       分析:DFS()的两个循环所需时间为O(V),traverse()中对每个结点的邻接表进行扫描,循环总次数加起来为O(E),所以时间复杂度为O(V+E)。

  • 相关阅读:
    JDBC在getConnection之前为什么要调用Class.forName(转)
    ThreadPoolExecutor的一点理解 专题
    java.lang.NoSuchMethodError
    POJ 3380 最大流
    Spring3.0 AOP 具体解释
    深入浅出 RPC
    JUnit入门
    Linux makefile 教程 很具体,且易懂
    怎样修复“Windows/System32/Config/System中文件丢失或损坏”故障
    MessageDigest简单介绍
  • 原文地址:https://www.cnblogs.com/magic-sea/p/11442479.html
Copyright © 2011-2022 走看看