其實這兩個算法思想很好理解。
深度優先遍歷:
- 在一個圖中選擇一個起始點v0,然後遍歷其子節點。
- 再以子節點爲起始點,遍歷子節點的子節點。
- 就這樣一直遞歸下去,重複2。
- 然後一直遍歷到沒有子節點,開始回溯。
廣度優先遍歷:
- 從圖中某個頂點v0出發,並訪問此頂點。
- 從v0出發,訪問V0的各個未曾訪問的鄰接點W1,W2,…,Wk;然後,依次從W1,W2,…,Wk出發訪問各自未被訪問的鄰接點。
- 重複步驟2,直到全部頂點都被訪問爲止。
(顯然,從v0出發廣度優先遍歷圖,將得到v0到它的各個可達到的路徑)
下面開始上菜:
前期造圖代碼準備:
import java.io.IOException;
import java.util.Scanner;
public class graphTraversal {
private char[] vertex; //頂點集合
private int[][] matrix; //鄰接矩陣
private static final int INF = 999999; //最大值
private static int count = 0;
/**
* 創建圖
*/
public graphTraversal() {
Scanner sca = new Scanner(System.in);
int vertexNum = sca.nextInt(); //頂點數
int matrixNum = sca.nextInt(); //邊數
vertex = new char[vertexNum];
vertex = sca.next().toCharArray(); //初始化頂點
//初始化矩陣
matrix = new int [vertexNum][vertexNum];
for(int i = 0; i < vertexNum; i++)
for(int j = 0; j < vertexNum; j++)
matrix[i][j] = (i == j) ? 0 : INF;
for(int i = 0; i < matrixNum; i++) { //初始化邊的權值
char start = readChar(); //邊的起點
char end = readChar(); //邊的終點
int weight = sca.nextInt(); //邊的權值
int startInedx = getLocation(start); //獲取邊的起點座標
int endIndex = getLocation(end); //獲取邊的終點座標
if(startInedx == -1 || endIndex == -1) return;
matrix[startInedx][endIndex] = weight;
matrix[endIndex][startInedx] = weight;
}
sca.close();
}
/**
* 深度優先搜索遍歷圖
*/
public void DFS() {
boolean[] visited = new boolean[vertex.length]; //記錄頂點訪問標記
//初始化所有頂點都沒被訪問
for(int i = 0; i < vertex.length; i++)
visited[i] = false;
System.out.println("DFS遍歷:" );
for(int i = 0; i < vertex.length; i++) {
if(!visited[i])
DFS(i, visited);
}
System.out.println();
}
/**
* 深度優先搜索遍歷圖的遞歸實現
*/
private void DFS(int i, boolean[] visited) {
count++;
visited[i] = true;
if(count == vertex.length) {
System.out.println(vertex[i]);
}else {
System.out.print(vertex[i] + "————>");
}
//遍歷該頂點的所有鄰接頂點,若是沒有訪問過,Go on
for(int j = firstVertex(i); j >= 0; j = nextVertex(i, j)) {
if(!visited[j])
DFS(j, visited);
}
}
/**
* 廣度優先搜索(類比樹的層次遍歷)
*/
public void BFS() {
count = 0; //遍歷點數歸0
int head = 0;
int rear = 0;
int[] queue = new int[vertex.length]; //輔助隊列
boolean[] visited = new boolean[vertex.length]; //頂點訪問標記
for(int i = 0; i < vertex.length; i++)
visited[i] = false;
System.out.println("BFS:");
for(int i = 0; i < vertex.length; i++) {
if(!visited[i]) {
count++;
visited[i] = true;
if(count == vertex.length) {
System.out.print(vertex[i]);
}else {
System.out.print(vertex[i] + "————>");
}
queue[rear++] = i; //入隊列
}
while(head != rear) {
int j = queue[head++]; //出隊列
for(int k = firstVertex(j); k >= 0; k = nextVertex(j, k)) { //k是爲訪問的鄰接頂點
if(!visited[k]) {
visited[k] = true;
count++;
if(count == vertex.length) {
System.out.print(vertex[k]);
}else {
System.out.print(vertex[k] + "————>");
}
queue[rear++] = k;
}
}
}
}
System.out.println();
}
/**
* 返回頂點v的第一個鄰接頂點的索引,失敗返回-1
*/
private int firstVertex(int v) {
if(v < 0 || v > (vertex.length - 1))
return -1;
for(int i = 0; i < vertex.length; i++) {
if(matrix[v][i] != 0 && matrix[v][i] != INF) {
return i;
}
}
return -1;
}
/**
* 返回頂點v相對於w的下一個鄰接頂點的索引,失敗則返回-1
*/
private int nextVertex(int v, int j) {
if(v < 0 || v > (vertex.length - 1) || j < 0 || j > (vertex.length - 1))
return -1;
for(int i = j + 1; i < vertex.length; i++) {
if(matrix[v][i] != 0 && matrix[v][i] != INF)
return i;
}
return -1;
}
/**
* 讀取一個輸入字符
* @return
*/
private char readChar() {
char ch = '0';
do {
try {
ch = (char)System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
}while(!((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')));
return ch;
}
/**
* 返回字符的位置
*/
private int getLocation(char c) {
for(int i = 0; i < vertex.length; i++)
if(vertex[i] == c) return i;
return -1;
}
public static void main(String[] args) {
graphTraversal gra = new graphTraversal();
gra.DFS(); //深度優先遍歷
gra.BFS(); //廣度優先遍歷
}
}
測試數據:
輸入:
8 9
ABCDEFGH
A B 1
A C 1
B D 1
B E 1
D H 1
E H 1
C F 1
C G 1
F G 1
輸出: