深度優先遍歷
圖的深度優先遍歷類似於樹的先序遍歷,首先通過一個指定的節點開始遍歷,然后訪問第一個鄰接點,然后切換到這個節點判斷是否是否有鄰接點,如果有,判斷是否被訪問過,如果沒有被訪問過,則訪問這個節點,切換到這個節點重復上面的操作,如果沒有,會返回上一個節點進行判斷。 直到所有的節點都訪問完成。
因為需要保證一個節點只能訪問一次,所以我們需要一個Tag
數組,這個數組為boolean
型,因為節點都是存儲在一個一維數組
中,所以我們可以得到節點數組的下標去獲取對應標記數組中的值來判斷這個節點是否被訪問過
。
在鄰接表中,先去判斷這個節點的第一個鄰接點,切換到鄰接點,然后再去判斷這個鄰接點的第一個鄰接點,如果沒有,則會去上一層去判斷下一個鄰接點(如果有的話)知道所有節點都被遍歷完成。
如下圖的鄰接表
首先從A開始訪問,然后第一個鄰接點為B,切換到B節點,B節點的第一個節點為A,A已經訪問完成,所以會返回B,B也會返回A,A就會繼續遍歷下一個鄰接點,即C,最后遍歷結果為 A-B-D-C-E
代碼:
public class DFS {
boolean tag[];
public void dfsTraverse(AlGraph alGraph) {
VNode[] list = alGraph.getNodeList();
tag = new boolean[list.length];
for (int i = 0; i < list.length; i++) {
if (!tag[i]) {
dfs(alGraph, i);
}
}
System.out.println();
}
public void dfs(AlGraph alGraph, int v) {
tag[v] = true;
VNode[] list = alGraph.getNodeList();
System.out.print(list[v].getData() + " ");
ArcNode arc = list[v].getFirstArc();
while (arc != null) {
if (!tag[arc.getAdjVex()])
dfs(alGraph, arc.getAdjVex());
arc = arc.getNextArc();
}
}
}
廣度優先遍歷
圖的廣度優先遍歷類似於數的層次遍歷,首先選定一個節點,然后把這個節點的鄰接點全部訪問,然后再判斷下一個節點是否存在鄰接點,同時這個鄰接點沒有被訪問,遍歷這個節點的所有鄰接點,依次循環直到所有節點都被遍歷完畢。
同時廣度遍歷也需要一個標志數組來判斷節點是否被訪問,標志數組的原理和深度優先遍歷相同。
上圖的鄰接表進行廣度優先遍歷的時候,借助了隊列
來實現,先訪問A然后訪問A的同時會將BC入隊,訪問完了A以后會訪問B,此時,也會將B的鄰接點入隊,余下節點依次訪問,如果節點訪問過則不訪問,結果為A-B-C-D-E
這樣就實現了表的廣度優先遍歷。
代碼
public class BreadthSearch {
boolean tag[];
public void bfs(AlGraph alGraph) {
LinkedList<VNode> q = new LinkedList<>();
VNode[] list = alGraph.getNodeList();
tag = new boolean[list.length];
for (int i = 0; i < tag.length; i++) {
// 廣度遍歷
if (!tag[i]) {
tag[i] = true;
VNode n = new VNode();
q.add(list[i]);
while (!q.isEmpty()) {
n = q.poll();
System.out.print(n.getData()+" ");
ArcNode arc = n.getFirstArc();
while (arc != null) {
if (!tag[arc.getAdjVex()]) {
tag[arc.getAdjVex()] = true;
q.add(list[arc.getAdjVex()]);
}
arc = arc.getNextArc();
}
}
}
}
System.out.println();
}
}