在上一篇文章我们用java演示了图的数据结构以及图涉及到的深度优先遍历算法,本篇文章将继续演示图的广度优先遍历算法。广度优先遍历算法主要是采用了分层的思想进行数据搜索。其中也需要使用另外一种数据结构队列,本篇文章为了使代码更加优雅,所有使用java中Linkedlist集合来进行模拟队列。因为该集合有在队列尾部添加元素和从队头取出元素的API。

算法思想:

1.先访问一个元素,然后放到队列中,并且标记已经访问过该元素。

2.然后判断队列是否为空,不为空则取出队头元素。

3.然后取出队头元素的第一个邻接节点并判断该元素是否存在。

4.如果存在再次判断该元素有没有被访问过。

5.如果没有访问过则标记为访问过。同时放到队列中。

6.如果访问过则以头节点为前驱节点,第一个邻接节点为第二个参数查找队头节点的下面的邻接节点

代码以下图为参考:

代码如下:

  1. 1 import java.util.ArrayList;
  2. 2 import java.util.Arrays;
  3. 3 import java.util.LinkedList;
  4. 4
  5. 5
  6. 6 public class Graph {
  7. 7
  8. 8 //创建一个集合用来存放顶点
  9. 9 private ArrayList<String> arrayList;
  10. 10 //创建一个二位数组来作为邻接矩阵
  11. 11 private int[][] TwoArray;
  12. 12 //边的数目
  13. 13 private int numOfEdges;
  14. 14 //使用一个数组记录节点是否被访问过
  15. 15 private boolean[] isVisted;
  16. 16 public static void main(String[] args) {
  17. 17 Graph graph = new Graph(5);
  18. 18 //测试
  19. 19 String[] ver={"A","B","C","D","E"};
  20. 20 //将节点放到集合中
  21. 21 for (String s : ver) {
  22. 22 graph.InsertVex(s);
  23. 23 }
  24. 24 //设置边
  25. 25 //A-B A-C B-C B-D B-E
  26. 26 graph.InsertEdeges(0,1,1);
  27. 27 graph.InsertEdeges(0,2,1);
  28. 28 graph.InsertEdeges(1,2,1);
  29. 29 graph.InsertEdeges(1,3,1);
  30. 30 graph.InsertEdeges(1,4,1);
  31. 31 //显示
  32. 32 graph.Show();
  33. 33 graph.BFS();
  34. 34 }
  35. 35
  36. 36 //初始化数据
  37. 37 public Graph(int n){
  38. 38 arrayList=new ArrayList<>(n);
  39. 39 TwoArray=new int[n][n];
  40. 40 numOfEdges=0;
  41. 41 isVisted=new boolean[n];
  42. 42 }
  43. 43
  44. 44 /**
  45. 45 * 根据节点的下标返回第一个邻接节点的下标
  46. 46 * @param index 节点的下标
  47. 47 * @return
  48. 48 */
  49. 49 public int getFirstVex(int index){
  50. 50 for (int i = 0; i < arrayList.size(); i++) {
  51. 51 if(TwoArray[index][i]!=0){
  52. 52 return i;
  53. 53 }
  54. 54 }
  55. 55 return -1;
  56. 56 }
  57. 57
  58. 58 /**
  59. 59 * 根据前一个节点下标获取下一个节点的下标
  60. 60 * @param v1 找到的第一个节点的
  61. 61 * @param v2 找到的第一个邻接节点并且被访问过的
  62. 62 * @return
  63. 63 */
  64. 64 public int getNextVex(int v1,int v2){
  65. 65 for (int i = v2+1; i < numEdges(); i++) {
  66. 66 if(TwoArray[v1][i]!=0){
  67. 67 return i;
  68. 68 }
  69. 69 }
  70. 70 return -1;
  71. 71 }
  72. 72
  73. 73 /**
  74. 74 * 广度优先遍历
  75. 75 * @param isVisted 记录是否被访问过的数组
  76. 76 * @param i 想要访问的节点下标
  77. 77 */
  78. 78 public void BFS(boolean[] isVisted,int i){
  79. 79 //表示队列头节点的下标
  80. 80 int u;
  81. 81 //用于存放队列头节点的第一个邻接节点
  82. 82 int w;
  83. 83 //定义一个队列用来存放节点
  84. 84 LinkedList<Object> queue = new LinkedList<>();
  85. 85 //访问该节点
  86. 86 System.out.print(getValue(i)+"->");
  87. 87 //在数组中标记为该下标已经被访问过了
  88. 88 isVisted[i]=true;
  89. 89 //把访问过的节点下标放到队列中,放到队列的尾部
  90. 90 queue.addLast(i);
  91. 91 //判断队列是否为空
  92. 92 while (!queue.isEmpty()){
  93. 93 //队列不为空,那么取出队列的头节点的下标
  94. 94 u=(Integer) queue.removeFirst();
  95. 95 //获取头节点的第一个邻接节点的下标
  96. 96 w = getFirstVex(u);
  97. 97 //判断该节点是否存在
  98. 98 while (w!=-1){
  99. 99 //说明存在,在判断是否被访问过
  100. 100 if(!isVisted[w]){
  101. 101 //没有访问过,标记为已访问
  102. 102 isVisted[w]=true;
  103. 103 //输出
  104. 104 System.out.print(getValue(w)+"->");
  105. 105 //访问完加入队列中
  106. 106 queue.addLast(w);
  107. 107 }
  108. 108 //以u作为前驱节点,w作为u刚刚访问过的节点,来查找w的下一个邻接节点
  109. 109 w = getNextVex(u, w);
  110. 110 }
  111. 111 }
  112. 112 }
  113. 113
  114. 114 public void BFS(){
  115. 115 for (int i = 0; i < arrayList.size(); i++) {
  116. 116 if(!isVisted[i]){
  117. 117 BFS(isVisted,i);
  118. 118 }
  119. 119 }
  120. 120 }
  121. 121
  122. 122 /**
  123. 123 * 添加节点
  124. 124 * @param vex
  125. 125 */
  126. 126 public void InsertVex(String vex){
  127. 127 arrayList.add(vex);
  128. 128 }
  129. 129
  130. 130 /**
  131. 131 * 设置边
  132. 132 * @param v1 第一个节点对应的下标
  133. 133 * @param v2 第二节点对应的下标
  134. 134 * @param weight 两个节点对应的权值
  135. 135 */
  136. 136 public void InsertEdeges(int v1,int v2,int weight){
  137. 137 TwoArray[v1][v2]=weight;
  138. 138 TwoArray[v2][v1]=weight;
  139. 139 numOfEdges++;
  140. 140 }
  141. 141
  142. 142 /**
  143. 143 * 返回节点对应的个数
  144. 144 * @return
  145. 145 */
  146. 146 public int numVex(){
  147. 147 return arrayList.size();
  148. 148 }
  149. 149
  150. 150 /**
  151. 151 * 返回边的总个数
  152. 152 * @return
  153. 153 */
  154. 154 public int numEdges(){
  155. 155 return numOfEdges;
  156. 156 }
  157. 157
  158. 158 /**
  159. 159 * 显示邻接矩阵(图的展示)
  160. 160 */
  161. 161 public void Show(){
  162. 162 for (int[] ints : TwoArray) {
  163. 163 System.out.println(Arrays.toString(ints));
  164. 164 }
  165. 165 }
  166. 166
  167. 167 /**
  168. 168 * 根据下标获取对应的数据
  169. 169 * @param i 下标
  170. 170 * @return
  171. 171 */
  172. 172 public String getValue(int i){
  173. 173 return arrayList.get(i);
  174. 174 }
  175. 175
  176. 176 public int getWeight(int v1,int v2){
  177. 177 int weight=TwoArray[v1][v2];
  178. 178 return weight;
  179. 179 }
  180. 180 }

图的广度优先遍历算法(BFS)的更多相关文章

  1. 《图论》——广度优先遍历算法(BFS)

    十大算法之广度优先遍历: 本文以实例形式讲述了基于Java的图的广度优先遍历算法实现方法,详细方法例如以下: 用邻接矩阵存储图方法: 1.确定图的顶点个数和边的个数 2.输入顶点信息存储在一维数组ve ...

  2. 数据结构与算法之PHP用邻接表、邻接矩阵实现图的广度优先遍历(BFS)

    一.基本思想 1)从图中的某个顶点V出发访问并记录: 2)依次访问V的所有邻接顶点: 3)分别从这些邻接点出发,依次访问它们的未被访问过的邻接点,直到图中所有已被访问过的顶点的邻接点都被访问到. 4) ...

  3. 图的广度优先遍历(bfs)

    广度优先遍历: 1.将起点s 放入队列Q(访问) 2.只要Q不为空,就循环执行下列处理 (1)从Q取出顶点u 进行访问(访问结束) (2)将与u 相邻的未访问顶点v 放入Q, 同时将d[v]更新为d[ ...

  4. 图文详解两种算法:深度优先遍历(DFS)和广度优先遍历(BFS)

    参考网址:图文详解两种算法:深度优先遍历(DFS)和广度优先遍历(BFS) - 51CTO.COM 深度优先遍历(Depth First Search, 简称 DFS) 与广度优先遍历(Breath ...

  5. PTA 邻接表存储图的广度优先遍历(20 分)

    6-2 邻接表存储图的广度优先遍历(20 分) 试实现邻接表存储图的广度优先遍历. 函数接口定义: void BFS ( LGraph Graph, Vertex S, void (*Visit)(V ...

  6. 饥饿的小易(枚举+广度优先遍历(BFS))

    题目描述 小易总是感觉饥饿,所以作为章鱼的小易经常出去寻找贝壳吃.最开始小易在一个初始位置x_0.对于小易所处的当前位置x,他只能通过神秘的力量移动到 4 * x + 3或者8 * x + 7.因为使 ...

  7. PTA 邻接表存储图的广度优先遍历

    试实现邻接表存储图的广度优先遍历. 函数接口定义: void BFS ( LGraph Graph, Vertex S, void (*Visit)(Vertex) ) 其中LGraph是邻接表存储的 ...

  8. 算法学习 - 图的广度优先遍历(BFS) (C++)

    广度优先遍历 广度优先遍历是非经常见和普遍的一种图的遍历方法了,除了BFS还有DFS也就是深度优先遍历方法.我在我下一篇博客里面会写. 遍历过程 相信每一个看这篇博客的人,都能看懂邻接链表存储图. 不 ...

  9. 怎样实现广度优先遍历(BFS)

    BFS过程: 一:訪问顶点V,并标记V为已经訪问 二:顶点V入队列 三:假设队列非空.进行运行,否则算法结束 四:出队列取得对头顶点u,假设顶点未被訪问,就訪问该顶点,并标记该顶点为已经訪问 五:查找 ...

随机推荐

  1. sql删除重复数据思路

    总的思路就是先找出表中重复数据中的一条数据,插入临时表中,删除所有的重复数据,然后再将临时表中的数据插入表中.所以重点是如何找出重复数据中的一条数据,有三种情况 1.重复数据完全一样,使用distin ...

  2. http ContentLength 为0 下载问题

    如图 通过http 下载某个东西 ,    WebResponse response = request.GetResponse(); response 调试如图 ContentLength 为0  ...

  3. slice,splice,split,unshift的用法

    工作了很久始终对这4个用法处于混淆状态,今天写个帖子来警示下自己 // slice(start,end),从start值开始截取到end前的元素组成新的数组,不改变原数组 // slice(index ...

  4. Sublime Text 3 习惯插件 转

    原帖:https://www.cnblogs.com/hykun/p/sublimeText3.html Emmet插件 Emmet插件可以说是使用Sublime Text进行前端开发必不可少的插件 ...

  5. docker基本入门知识-小白向

    基本概念 Docker是一个开源项目,前身是dotCloud公司的内部项目,但苦于无法扩大使用和推广,后期开源后吸引大量的开发人员的参与,以至于公司直接改名为Docker Inc. Docker项目的 ...

  6. Oracle 模糊查询 优化

    模糊查询是数据库查询中经常用到的,一般常用的格式如下: (1)字段  like '%关键字%'   字段包含"关键字"的记录   即使在目标字段建立索引也不会走索引,速度最慢 (2 ...

  7. i5 11300H和i5 10300H 的区别

    i5-11300H 为 4 核 8 线程,主频 3.1GHz,睿频 4.4GHz,三级缓存 8MB 选 i5-11300H还是i5 10300h 这些点很重要!看完你就知道了https://list. ...

  8. linux安装ftp步骤

    1,查看是否安装了FTP:rpm -qa |grep vsftpd 2,如果没有安装,可以使用如下命令直接安装 yum -y install vsftpd 默认安装目录:/etc/vsftpd 3,添 ...

  9. 牺牲速度来节省内存,Redis是觉得自己太快了吗

    前言 正常情况下我们选择使用 Redis 就是为了提升查询速度,然而让人意外的是,Redis 当中却有一种比较有意思的数据结构,这种数据结构通过牺牲部分读写速度来达到节省内存的目的,这就是 zipli ...

  10. ajax跨域访问http服务--jsonp

    在前面一篇文章<Spring Cloud 前后端分离后引起的跨域访问解决方案>里我们提到使用ajax跨域请求其他应用的http服务,使用的是后台增加注解@CrossOrigin或者增加Co ...