上一篇文章跟大家讲了图的深度优先遍历算法,今天跟大家分享一下图的广度优先遍历,图的广度优先搜索(BFS)类似于一个分层搜索的过程,广度优先遍历需要使用一个队列用以保存访问过的结点的顺序,一边按照这个顺序来访问这些结点的邻接结点。
广度优先遍历算法步骤(伪代码):
- 访问初始结点v,并标记结点v为已访问
- 结点v进入队列(队列必须从尾部加入,从头部取出)
- 当队列非空时,继续执行,否则对该结点的算法结束
- 取得队列的头结点u,并出队列
- 查找结点u的第一个邻接结点w
- 若结点u的邻接结点不存在,则转到步骤3,否则循环以下三个步骤
1)若结点w尚未被访问,则访问结点w并标记为已访问
2)结点w入队列
3)若结点w已经被访问,查找结点u的继w邻接结点之后的下一个邻接结点w,转到步骤6
广度优先遍历与深度优先遍历类似,只不过遍历树匈奴一个是纵向的一个是横向的,因此所有方法均可以共用,代码如下,代码均为自己手敲:
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */package graph;import java.util.ArrayList;import java.util.Arrays;import java.util.LinkedList;/** * * @author Administrator */public class Graph { /** * @param args the command line arguments */ private ArrayList vertexList; //存储结点集合 private int [][]edges; //存储图对应的邻接矩阵 private int numOfEdges; // 表示边的数目 private boolean[] isVisited; public static void main(String[] args) { // 测试代码 int n=5; //结点个数 String Vertexs[] ={"A","B","C","D","E"}; //创建图对象 Graph graph = new Graph(n); //循环添加节点 for(String vertexvalue: Vertexs){ graph.insertVertex(vertexvalue); } //添加边 graph.insertEdges(0, 1, 1); graph.insertEdges(0, 2, 1); graph.insertEdges(1, 2, 1); graph.insertEdges(1, 3, 1); graph.insertEdges(1, 4, 1); //显示邻接矩阵 graph.showGraph(); System.out.println("深度遍历"); graph.dfs(); System.out.println(" "); System.out.println("广度优先遍历"); graph.bfs(); } //构造器 public Graph(int n){ //构造图需要知道该图有多少个结点 //初始化矩阵和vertexList edges = new int[n][n]; vertexList =new ArrayList(n); numOfEdges = 0; isVisited = new boolean[5]; } //得到第一个邻接结点的下标,如果存在就返回对应的下标,否则返回-1 public int getFirstNeighbor(int index){ for(int j=0;j if(edges[index][j]>0){ return j; } } return -1; } //根据前一个邻接结点的下标来获取下一个邻接结点 public int getNextNeighbor(int v1, int v2){ for(int j= v2+1 ;j < vertexList.size(); j++){ if(edges[v1][j]>0){ return j; } } return -1; } //深度优先遍历算法 public void dfs(boolean[] isVisited, int i){ //首先访问该结点输出 System.out.print(getValueByIndex(i)+"->"); //将这个结点设置为已经访问 isVisited[i]=true; //查找结点i的第一个邻接结点w int w = getFirstNeighbor(i); while(w!=-1){ //说明有邻接结点 if(isVisited[w]!=true){ dfs(isVisited,w); } //如果w结点已经被访问 w=getNextNeighbor(i,w); } } //对dfs进行一个重载,遍历所有结点并进行dfs public void dfs(){ isVisited = new boolean[5]; for(int i=0;i if(isVisited[i]!=true){ dfs(isVisited,i); } } } //对一个结点进行广度遍历优先的方法 private void bfs(boolean[] isVisited,int i){ int u; //队列头结点对应的下标 int w; //邻接结点的下标 //队列,记录结点访问顺序 LinkedList queue = new LinkedList(); //访问该结点 并输出结点信息 System.out.print(getValueByIndex(i)+"->"); //标记为以访问 isVisited[i]=true; //将结点加入队列 queue.addLast(i); while(!queue.isEmpty()){ //取出队列的头结点下标 u=(Integer)queue.removeFirst(); //得到结点u的第一个邻接结点w w=getFirstNeighbor(u); // System.out.println(w); while(w!=-1){ //找到结点u的邻接结点 if(!isVisited[w]){ System.out.print(getValueByIndex(w)+"->"); //标记已经访问 isVisited[w]=true; //入队列 queue.addLast(w); //以u为前驱点,找w后面的邻接结点 } w=getNextNeighbor(u,w); // System.out.println(w); } } } //遍历所有的结点都进行广度优先搜索 public void bfs(){ isVisited = new boolean[5]; for(int i=0;i if(!isVisited[i]){ bfs(isVisited,i); } } } //图中常用的方法 //返回插入结点的个数 public int getNumOfVertex(){ return vertexList.size(); } //得到边的数目 public int getNumOfEdges(){ return numOfEdges; } //返回结点i对应的下标的数据 0-A 1-B 2-C public String getValueByIndex(int i){ return vertexList.get(i); } //返回v1和v2的权值 public int getWeight(int v1,int v2){ return edges[v1][v2]; } //显示图对应的矩阵 public void showGraph(){ for(int[] link :edges){ System.out.println(Arrays.toString(link)); } } //插入结点 public void insertVertex(String vertex){ vertexList.add(vertex); } //添加边 // v1 v2 表示点的下标 public void insertEdges(int v1, int v2,int weight){ edges[v1][v2]=weight; edges[v2][v1]=weight; numOfEdges++; }}
其中第100行到第143行,为BFS具体实现的代码,运行之后,结果如下图所示:
从控制台可以得出,深度优先与广度优先遍历对于同一个图来说,得到的结果是相同的,以上就是遍历图中结点的两种方法,谢谢大家。