图的遍历
图的遍历指的是从图中的任一顶点出发,对图中的所有顶点访问一次且只访问一次。图的遍历操作和树的遍历操作功能相似。图的遍历是图的一种基本操作,图的许多其它操作都是建立在遍历操作的基础之上。
根据访问节点的顺序,我们可以分成两种方法来对图进行遍历。分别是深度优先遍历(DFS)和广度优先遍历(BFS)。
DFS
算法思想:
从某个点一直往深处走,走到不能往下走之后,就回退到上一步,直到找到解或把所有点走完。
算法步骤(递归或栈实现)
- 访问指定起始地点。
- 若当前访问顶点的邻接顶点有未被访问的顶点,就任选一个访问。如果没有就回退到最近访问的顶点,直到与起始顶点相通的所有点被遍历完。
- 若途中还有顶点未被访问,则再选一个点作为起始顶点。重复步骤2(针对非连通图)。
算法实现
import java.util.Stack;
public class Demo_01_DFS {
//递归版DFS
public static void DFSbyRecursion(int[][] graph){
int length = graph.length;
boolean[] visited = new boolean[length];
//为了预防图不是连通图的情况,若图为连通图则直接调用DFS,不需要for循环
for (int i = 0; i < length; i++) {
if(!visited[i])
DFS(graph,i,visited);
}
}
public static void DFS(int[][] graph,int vertex,boolean[] visited){
visited[vertex] = true;
//遍历该点
System.out.print(vertex + " ");
int length = graph.length;
for (int i = 0; i < length; i++) {
//找出与vertex相邻的点,进行DFS。找到一个点就DFS,遍历到底了就进行回退(这里注意递归的过程,)
if(!visited[i] && graph[vertex][i] == 1){
DFS(graph,i,visited);
}
}
}
//用栈实现DFS
public static void DFSbyStack(int[][] graph){
Stack<Integer> stack = new Stack<>();
int length = graph.length;
//判断元素是否被遍历过
boolean[] visited = new boolean[length];
for (int i = 0; i < length; i++) {
if(!visited[i]){
stack.push(i);
visited[i] = true;
boolean hasNext;
//遍历第一个点
System.out.print( i+ " ");
while(!stack.empty()){
//取出栈顶元素
int temp = stack.peek();
//设置变量来判断是否有新点入栈,没有就弹出栈顶元素,有的话进行下一次循环。
hasNext = false;
for (int j = 0; j < length; j++) {
//找出一个与栈顶元素有连接且没有被遍历的点放入stack中,并遍历该点
if(!visited[j] && graph[temp][j] == 1){
stack.push(j);
visited[j] = true;
hasNext = true;
//遍历该点
System.out.print(j + " ");
break;
}
}
//如果没有下一个元素则回溯,删除栈顶元素
if (!hasNext){
stack.pop();
}
}
}
}
}
public static void main(String[] args) {
int[][] graph = {
{ 0, 1, 1, 0, 0 },
{ 0, 0, 1, 0, 1 },
{ 0, 0, 0, 0, 0 },
{ 1, 1, 0, 0, 1 },
{ 0, 0, 1, 0, 0 }
};
DFSbyRecursion(graph);
System.out.println();
DFSbyStack(graph);
}
}
BFS
算法思想
从某个点一直把其邻接点走完,然后任选一个邻接点把与之邻接的未被遍历的点走完,如此反复走完所有结点。类似于树的层序遍历。
算法步骤(用队列实现)
- 访问指定起始点。
- 访问当前顶点的邻接顶点有未被访问的顶点,并将之放入队列中。
- 删除队列的队首节点。访问当前队列的队首,重复步骤2。直到队列为空。
- 若若途中还有顶点未被访问,则再选一个点作为起始顶点。重复步骤2。(针对非连通图)。
算法实现
import java.util.LinkedList;
import java.util.Queue;
public class Demo_02_BFS {
//用队列来实现BFS
public static void BFSbyQueue(int[][] graph){
Queue<Integer> queue = new LinkedList<>();
int length = graph.length;
boolean[] visited = new boolean[length];
//为了预防图不是连通图的情况,若图为连通图则不需要for循环
for (int i = 0; i < length; i++) {
if(!visited[i]){
queue.add(i);
visited[i] = true;
System.out.print(i + " ");
while(queue.size() != 0){
int temp = queue.poll();
//遍历所有与temp相邻的点,依次加入队列中,并遍历他们
for (int j = 0; j < length; j++) {
if(!visited[j] && graph[temp][j] == 1){
queue.add(j);
visited[j] = true;
System.out.print(j + " ");
}
}
}//while
}
}
}
public static void main(String[] args) {
int[][] graph = {
{ 0, 1, 0, 1, 0 },
{ 0, 0, 1, 0, 1 },
{ 0, 0, 0, 0, 0 },
{ 1, 1, 0, 0, 1 },
{ 0, 0, 1, 0, 0 }
};
BFSbyQueue(graph);
}
}