圖的遍歷
圖的遍歷指的是從圖中的任一頂點出發,對圖中的所有頂點訪問一次且只訪問一次。圖的遍歷操作和樹的遍歷操作功能相似。圖的遍歷是圖的一種基本操作,圖的許多其它操作都是建立在遍歷操作的基礎之上。
根據訪問節點的順序,我們可以分成兩種方法來對圖進行遍歷。分別是深度優先遍歷(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);
}
}