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

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

原文地址:https://www.cnblogs.com/magic-sea/p/11442479.html

时间: 2024-11-09 02:10:19

图的优先遍历:广度优先搜索和深度优先搜索的相关文章

【图论】广度优先搜索和深度优先搜索

写在最前面的 这篇文章并没有非常详细的算法证明过程.导论里面有非常详细的证明过程.本文只阐述“广度优先和深度优先搜索的思路以及一些简单应用”. 两种图的遍历算法在其他图的算法当中都有应用,并且是基本的图论算法. 广度优先搜索 广度优先搜索(BFS),可以被形象的描述为“浅尝辄止”,具体一点就是每个顶点只访问它的邻接节点(如果它的邻接节点没有被访问)并且记录这个邻接节点,当访问完它的邻接节点之后就结束这个顶点的访问. 广度优先用到了“先进先出”队列,通过这个队列来存储第一次发现的节点,以便下一次的

Java 实现广度优先搜索和深度优先搜索

1. 综述 复习算法数据结构,用Java 实现广度优先搜索和深度优先搜索. 2. 代码 要搜索的图为: Java代码: 1 package cn.edu.tju.scs; 2 3 import java.util.LinkedList; 4 import java.util.Queue; 5 6 public class Search { 7 public static boolean [] accessed = new boolean[8]; 8 public static boolean [

总结A*,Dijkstra,广度优先搜索,深度优先搜索的复杂度比较

广度优先搜索(BFS) 1.将头结点放入队列Q中 2.while Q!=空 u出队 遍历u的邻接表中的每个节点v 将v插入队列中 当使用无向图的邻接表时,复杂度为O(V^2) 当使用有向图的邻接表时,因为每条边只访问一次,不会重复访问,所以总复杂度为O(V+E) 深度优先搜索(DFS) for each vertex u∈V(G)    //执行时间为O(V) DFS(u) DFS内部: for each v 为u的邻接点      //执行时间为O(E) DFS(v) 总执行时间为O(V+E)

有关搜索和深度优先搜索的浅陋见解

祝食用愉快XD 题目链接 (是一道胡乱出的题) U56815 来走迷宫鸭! 解题思路 深度优先搜索,如果能不碰墙地到达右下角的出口,就把旗子立起来表示找到了出口. 什么?你没听过深度优先搜索 没事,且听我道来. 什么是搜索?如何搜索? 简单来说,搜索就是一种特殊的(递归的)枚举.从一种可行的方案进行扩展,并去看这个扩展出来的东西符不符合现有规则.能不能继续扩展. 可是你讲理论我也听不懂啊 那,深度优先搜索又是什么呢? 拿走迷宫这事儿说起.如果你玩过\(MC\),或者无论从哪个去掉了解走迷宫的时候

图的表示、广度优先搜索、深度优先搜索

1.图的表示 a.邻接矩阵:适合稠密图(|E|接近|V|2) //用二维数组表示邻接矩阵 int G[|V|][|V|]; //初始化 for(int i=0;i<|V|;i++){ for(int j=0;j<|V|;j++){ if( (i,j) in E){ G[i][j] = 1;//or G[i][j] = weight[i][j]; } else if(i==j){ G[i][j] = 0; } else{ G[i][j] = MAX; } } } b.邻接表:适合稀疏图(|E|远

【算法】图的广度优先搜索和深度优先搜索

我们构建一张如下的图: 直接上代码: package main; import java.util.ArrayList; public class Node { private String name = ""; public ArrayList<Node> neighbor = new ArrayList<>(); public boolean flag = false; public Node(String name){ this.name = name;

广度优先搜索、深度优先搜索

package com.tyson.graph; import java.util.ArrayList; import java.util.LinkedList; import java.util.Queue; public class GraphMatrix { private ArrayList<Integer> vertexList; private int[][] edges; private int edgesNum; public GraphMatrix(int n) { edge

图的遍历之深度优先搜索(Depth-First Search—DFS)

描述 从根节点开始的递归深度优先搜索与树的前序遍历(preorder traversal)类似,是前序遍历的推广.从某个顶点V开始处理,然后递归地遍历所有与顶点V邻接的且没有被访问过的顶点.算法的基本思想如下: 假设图G初态为所有顶点未被访问(visited[i]=false),从G中任选一顶点vi : 从该顶点vi出发,首先访问vi,,置visited [vi ]=true; 然后依次搜索vi的每一个邻接点vj : 若vj未被访问过,则以vj为新的初始出发点,重复1:若vj已被访问过,则返回到

&quot;《算法导论》之‘图’&quot;:深度优先搜索、宽度优先搜索及连通分量

本文兼参考自<算法导论>及<算法>. 以前一直不能够理解深度优先搜索和广度优先搜索,总是很怕去碰它们,但经过阅读上边提到的两本书,豁然开朗,马上就能理解得更进一步.  1. 深度优先搜索  1.1 迷宫搜索 在<算法>这本书中,作者写了很好的一个故事.这个故事让我马上理解了深度优先搜索的思想. 如下图1-1所示,如何在这个迷宫中找到出路呢?方法见图1-2. 图1-1 等价的迷宫模型 探索迷宫而不迷路的一种古老办法(至少可以追溯到忒修斯和米诺陶的传说)叫做Tremaux搜