图的广度优先遍历基本思想:
- 横向搜索,遍历完一个顶点的所有邻接顶点后,再遍历其他顶点的邻接顶点。
- 需要使用一个队列,用来保存被首次访问的顶点,然后按照顺序弹出进行遍历。
举一个具体例子:
对上图进行BFS:
- 首先访问初始顶点A,将其加入队列
- 判断队列是否为空,若不为空,则弹出队尾一个顶点,遍历该顶点的所有邻接顶点
- 在上述遍历过程中,如果有首次访问的邻接顶点,需要将其加入队列
- 所有邻接顶点遍历完后,再次判断队列是否为空,若不为空,重复1~4步骤;若为空,则程序结束。
package DataStructure;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
public class GraphDemo {
public static void main(String[] args) {
Graph graph = new Graph(5);
String[] vertexS = {"A", "B", "C", "D", "E"};
for (String vertex : vertexS) {
graph.insertVertex(vertex);
}
// A-B A-C B-C B-D B-E
graph.insertEdge(0, 1, 1);
graph.insertEdge(0, 2, 1);
graph.insertEdge(1, 2, 1);
graph.insertEdge(1, 3, 1);
graph.insertEdge(1, 4, 1);
graph.showGraph();
System.out.println();
// graph.depthFirstSearch();
graph.broadFirstSearch();
}
}
class Graph {
private ArrayList<String> vertexList; // 储存顶点
private int[][] edges; // 储存邻接矩阵
private int edgesNum; // 储存边的个数
// 定义一个boolean数组,记录某个顶点是否被访问过,用于遍历
private boolean[] isVisited;
// 定义一个队列用于BFS
Queue<Integer> queue = new LinkedList<>();
public Graph(int n) {
vertexList = new ArrayList<>(n);
edges = new int[n][n];
isVisited = new boolean[n];
}
// 常用方法:
// 插入顶点
public void insertVertex(String vertex) {
vertexList.add(vertex);
}
/**
* 添加边
* @param v1 顶点的下标
* @param v2 另一个顶点的下标
* @param flag 1或0 表示直接连接或不直接连接
*/
public void insertEdge(int v1, int v2, int flag) {
edges[v1][v2] = flag;
edges[v2][v1] = flag;
edgesNum++;
}
// 返回顶点个数
public int getVertexNum() {
return vertexList.size();
}
// 返回边的数目
public int getEdgesNum() {
return edgesNum;
}
// 返回下标i对应的顶点数据
public String getVertex(int i) {
return vertexList.get(i);
}
// 返回两个顶点的连接关系
public int getFlag(int v1, int v2) {
return edges[v1][v2];
}
// 显示图对应的矩阵
public void showGraph() {
for (int[] edge : edges) {
System.out.println(Arrays.toString(edge));
}
}
// 获取当前节点的第一个邻接顶点
public int getFirstVertex(int index) {
for (int i = 0; i < vertexList.size(); i++) {
if (edges[index][i] == 1) {
return i;
}
}
return -1;
}
/**
* 获取当前顶点在某个邻接顶点之后的第一个邻接顶点
* @param v1 当前顶点下标
* @param v2 某个邻接顶点的下标
* @return 返回某个邻接顶点之后的第一个邻接顶点的下标,未找到则返回-1
*/
public int getNextVertex(int v1, int v2) {
for (int i = v2 + 1; i < vertexList.size(); i++) {
if (edges[v1][i] == 1) {
return i;
}
}
return -1;
}
// BFS
public void broadFirstSearch(int i) {
System.out.println(getVertex(i));
isVisited[i] = true;
queue.add(i);
while (!queue.isEmpty()) {
int u = queue.poll();
int w = getFirstVertex(u);
while (w != -1) {
if (!isVisited[w]) {
System.out.println(getVertex(w));
isVisited[w] = true;
queue.add(w);
}
w = getNextVertex(u, w);
}
}
}
public void broadFirstSearch() {
for (int i = 0; i < vertexList.size(); i++) {
if (!isVisited[i]) {
broadFirstSearch(i);
}
}
}
}