图的优先遍历:广度优先搜索和深度优先搜索

Posted magic-sea

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图的优先遍历:广度优先搜索和深度优先搜索相关的知识,希望对你有一定的参考价值。

广度优先搜索,该算法是将已发现结点和未发现结点之间的边界,沿着其广度方向向外扩展,算法需要发现所有距离源结点 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)。

以上是关于图的优先遍历:广度优先搜索和深度优先搜索的主要内容,如果未能解决你的问题,请参考以下文章

图的深度/广度优先遍历C语言程序

图的遍历之深度优先搜索和广度优先搜索

基本算法——深度优先搜索(DFS)和广度优先搜索(BFS)

数据结构学习笔记——图的遍历(深度优先搜索和广度优先搜索)

图的遍历(深度优先和广度优先)

图的优先遍历:广度优先搜索和深度优先搜索