1.前言
以图邻接矩阵的存储方式介绍图的深度优先遍历和图的广度优先遍历。
以下图的图为例简单介绍图的邻接矩阵存储方式。
上图共有9个顶点,15条边,我们用一个二维矩阵来存储顶点之间的连接关系,上图的邻接矩阵如下(0代表两个顶点之间不可达,1代表两个顶点邻接)。
A | B | C | D | E | F | G | H | I | |
---|---|---|---|---|---|---|---|---|---|
A | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
B | 1 | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 1 |
C | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 1 |
D | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 1 | 1 |
E | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 0 |
F | 1 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 |
G | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 0 |
H | 0 | 0 | 0 | 1 | 1 | 0 | 1 | 1 | 0 |
I | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 1 |
2.图的深度优先遍历
- 从图的某个顶点V出发,访问此顶点,然后从v的未被访问的邻接点出发接着遍历,直至图中所有和V邻接的顶点都被访问到。
- 若图中还有节点未访问到,就另选一个未访问的顶点,重复步骤1,直到所有顶点被访问完。
主要代码如下。
//步骤1 i代表顶点下标
void DFS(int i) {
System.out.print(vertexes[i] + " ");
visited[i] = true;//访问此顶点
for(int j = 0; j < numVertexes; j++) {//递归访问其邻接顶点
if(adjacentMatrix[i][j] == 1 && !visited[j]) {
DFS(j);
}
}
}
//步骤2
void DFSTraverse() {
//重置所有顶点未访问
for(int i = 0; i < numVertexes; i++)
visited[i] = false;
System.out.println("深度优先:");
for(int i = 0; i < numVertexes; i++) {//选一个未访问的顶点,进行步骤1
if(!visited[i]) {
DFS(i);
}
}
}
3.图的广度优先遍历
- 首先访问初始点Vi,并将其标记为已访问过。
- 接着访问步骤1中的Vi的所有未被访问过的邻接点Vi1,Vi2,…,,Vit,并均标记已访问过。
- 然后再按照Vi1,Vi2,…,,Vit的次序,访问每一个顶点的所有未被访问过的邻接点,并均标记为已访问过,直到图中所有和初始点vi有路径相通的顶点都被访问过为止。
我们用一个辅助队列存储访问过程中的顶点信息,主要代码如下。
void BFSTraverse() {
//重置所有顶点未访问
for(int i = 0; i < numVertexes; i++)
visited[i] = false;
Queue<Integer> Q = new LinkedList<>();//链表实现的辅助队列
System.out.println("\n广度优先:");
for(int i = 0; i < numVertexes; i++) {
if(!visited[i]) {//如果当前顶点未访问
System.out.print(vertexes[i] + " ");
visited[i] = true;//访问该顶点
Q.offer(i);//将该顶点放入辅助队列
while(!Q.isEmpty()) {
int temp = Q.poll();//队头弹出队列
for(int j = 0; j < numVertexes; j++) {//访问队头的邻接顶点
if(adjacentMatrix[temp][j] == 1 && !visited[j]) {
System.out.print(vertexes[j] + " ");
visited[j] = true;//访问邻接顶点
Q.offer(j);//将访问了的邻接顶点加入辅助队列
}
}
}
}
}
}
4.具体实现
具体的实现代码如下,示例图的测试数据在类的开始的注释。
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
/*
--测试数据--
9 15
0 1
0 5
1 2
1 8
1 6
2 3
2 8
3 4
3 7
3 6
3 8
4 5
4 7
5 6
6 7
*/
public class GraphTraverse {
int numVertexes, numEdges;//顶点数、边数
char[] vertexes;//顶点集
int[][] adjacentMatrix;//邻接矩阵
boolean[] visited;
//初始化图
void initGraph() {
Scanner in = new Scanner(System.in);
numVertexes = in.nextInt();
numEdges = in.nextInt();
vertexes = new char[numVertexes];
adjacentMatrix = new int[numVertexes][numVertexes];
visited = new boolean[numVertexes];
for(int i = 0; i < this.numVertexes; i++) {
vertexes[i] = (char)(i + 'A');
}
for(int i = 0; i < numEdges; i++) {
adjacentMatrix[in.nextInt()][in.nextInt()] = 1;
}
for(int i = 0; i < numVertexes; i++) {
for(int j = i; j < numVertexes; j++) {
adjacentMatrix[j][i] = adjacentMatrix[i][j];
}
}
for(int i = 0; i < numVertexes; i++) {
for(int j = 0; j < numVertexes; j++) {
System.out.print(adjacentMatrix[i][j] + " ");
}
System.out.println();
}
}
void DFS(int i) {
System.out.print(vertexes[i] + " ");
visited[i] = true;
for(int j = 0; j < numVertexes; j++) {
if(adjacentMatrix[i][j] == 1 && !visited[j]) {
DFS(j);
}
}
}
void DFSTraverse() {
for(int i = 0; i < numVertexes; i++) {
visited[i] = false;
}
System.out.println("深度优先:");
for(int i = 0; i < numVertexes; i++) {
if(!visited[i]) {
DFS(i);
}
}
}
void BFSTraverse() {
for(int i = 0; i < numVertexes; i++) {
visited[i] = false;
}
Queue<Integer> Q = new LinkedList<>();
System.out.println("\n广度优先:");
for(int i = 0; i < numVertexes; i++) {
if(!visited[i]) {
visited[i] = true;
System.out.print(vertexes[i] + " ");
Q.offer(i);
while(!Q.isEmpty()) {
int temp = Q.poll();
for(int j = 0; j < numVertexes; j++) {
if(adjacentMatrix[temp][j] == 1 && !visited[j]) {
visited[j] = true;
System.out.print(vertexes[j] + " ");
Q.offer(j);
}
}
}
}
}
}
public static void main(String[] args) {
Graph G = new Graph();
G.initGraph();
G.DFSTraverse();
G.BFSTraverse();
}
}