数据结构之图的遍历

参考网址: https://www.jianshu.com/p/60eb50dbfc39java

若是是遍历一个数组,只须要从下标0到下标N-1循环就行了,遍历一个链表只须要从头指针开始直到没有next为止,即便是遍历一棵树,也能够从根结点开始,按照前序、中序和后序等方式进行。之因此能够这样,是由于这些结构均可以找到一个明确的起点,但图不一样。以下图所示,有的人但愿从A开始遍历,有的人喜欢从C开始...,没有办法规定一个明确的起点。git

 

 

 

若是没有策略,遍历一个图就像走迷宫同样,有可能在一个结点停留屡次,也可能有几个结点永远不会访问到。而图的遍历,一般有深度优先和广度优先方式,接下来咱们就看看这两种方式是怎么作的,有什么区别。github

深度优先遍历

深度优先遍历(Depth_First_Search)也称为深度优先搜索,简称为DFS。它是从图中某个顶点v出发,访问此顶点,而后从v的未被访问的邻接点出发深度优先遍历图,直至图中全部和v有路径相通的顶点都被访问到。对于非连通图,只须要对它的连通份量分别进行深度优先遍历便可。接下来咱们以一个示例演示图的深度优先遍历。以下图所示:数组

 

 

 

 
图的深度优先遍历

在开始进行遍历以前,咱们还要准备一个数组,用来记录已经访问过的元素。其中0表明未访问,1表明已访问,以下所示:spa

 

 

 

visited数组

为了便于演示,假设咱们是在走迷宫,A是入口,每次都向右手边前进。首先从A走到B,结果以下:3d

 

 

 

A-B

B以后有三个路,咱们依然选择最右边,如此下去,直到走到F,以下所示:指针

 

 

 

B-F

到达F后,若是咱们继续按照向右走的原则,就会再次访问A,此时咱们访问除了A后的最右侧通道,也就是访问G,以下所示:code

 

 

 

F-G

到达G后,能够发现B和D都走过了,这时候走到H,以下所示:blog

 

 

 

G-H

到达H后,能够发现D和E都走过了,也就是说走到了尽头,可是并不表明全部的顶点都访问过了,由于除了最右侧顶点,每一个顶点还可能和更多的顶点连通,因此咱们从H退回到G,发现所有走过了,再向前退回到F,也所有走过了,直到退回到B时,发现 I 还没走过,因而访问顶点 I,以下所示:token

 

 

 

B-I

同理,访问 I 以后,发现与 I 连通的顶点都访问过了,因此再向前回退,直到回到顶点A,发现所有顶点都访问过了,至此遍历完毕。

广度优先遍历

深度优先遍历能够认为是纵向遍历图,而广度优先遍历(Breadth_First_Search)则是横向进行遍历。还以上图为例,不过为了方便查看,咱们把上图调整为以下样式:

 

 

 

广度优先遍历图

咱们依然以A为起点,把和A邻接的B和F放在第二层,把和B、F邻接的C、I、G、E放在第三层,剩下的放在第四层。广度优先遍历就是从上到下一层一层进行遍历,这和树的层序遍历很像。咱们依然借助一个队列来完成遍历过程,由于和树的层序遍历很像,这里只展现结果,以下所示:

 

 

 

 
广度优先遍历队列

对于非连通图,依然经过visited数组来进行判断便可。

代码实现

图的存储方式有不少种,可是用来实现遍历的思路是一致的,咱们以邻接矩阵为例,给出DFS和BFS的参考实现。

深度优先遍历实现

private void DFS(int i) { // 标记当前元素已经访问 visited[i] = true; System.out.println("当前访问顶点:" + getVertexByIndex(i)); int next = getFirstNeighbor(i); while (next != -1) { if (!visited[next]) { DFS(next); } next = getNextNeighbor(i, next); } } public void DFS() { for (int i = 0; i < vertexList.size(); i++) { visited[i] = false; } // 非连通图,不一样的连通份量要单独进行DFS for (int i = 0; i < vertexList.size(); i++) { if (!visited[i]) { DFS(i); } } } 

广度优先遍历实现

private void BFS(int i) { // 标记当前元素已经访问 visited[i] = true; System.out.println("当前访问顶点:" + getVertexByIndex(i)); int cur, next; LinkedList<Integer> queue = new LinkedList<>(); queue.addLast(i); while (!queue.isEmpty()) { cur = queue.removeFirst(); next = getFirstNeighbor(cur); while (next != -1) { if (!visited[next]) { // 标记当前元素已经访问 visited[next] = true; System.out.println("当前访问顶点:" + getVertexByIndex(next)); queue.addLast(next); } next = getNextNeighbor(cur, next); } } } public void BFS() { for (int i = 0; i < vertexList.size(); i++) { visited[i] = false; } for (int i = 0; i < vertexList.size(); i++) { if (!visited[i]) { BFS(i); } } } 

完整代码已上传至个人github

做者:大大纸飞机 连接:https://www.jianshu.com/p/60eb50dbfc39 来源:简书 著做权归做者全部。商业转载请联系做者得到受权,非商业转载请注明出处。
相关文章
相关标签/搜索