【資料結構】圖(深度優先遍歷、廣度優先遍歷)的JAVA程式碼實現
阿新 • • 發佈:2019-02-03
圖的遍歷是指從圖中的任一頂點出發,對圖中的所有頂點訪問一次並且只訪問一次。圖的遍歷是圖的一種基本操作,圖中的許多其他操作也都是建立在遍歷的基礎之上。在圖中,沒有特殊的頂點被指定為起始頂點,圖的遍歷可以從任何頂點開始。圖的遍歷主要有深度優先搜尋和廣度優先搜尋兩種方式。
深度優先搜尋演算法
演算法的思想
從圖中的某一個頂點x出發,訪問x,然後遍歷任何一個與x相鄰的未被訪問的頂點y,再遍歷任何一個與y相鄰的未被訪問的頂點z……依次類推,直到到達一個所有鄰接點都被訪問的頂點為止;然後,依次回退到尚有鄰接點未被訪問過的頂點,重複上述過程,直到圖中的全部頂點都被訪問過為止。
演算法實現的思想
深度優先遍歷背後基於堆疊,有兩種方式:第一種是在程式中顯示構造堆疊,利用壓棧出棧操作實現;第二種是利用遞迴函式呼叫,基於遞迴程式棧實現。
- 訪問起始頂點,並將其壓入棧中;
- 從棧中彈出最上面的頂點,將與其相鄰的未被訪問的頂點壓入棧中;
- 重複第二步,直至棧為空棧。
未被訪問的頂點怎麼識別呢?利用visited陣列來進行標記。
演算法的實現
基於鄰接矩陣的演算法實現:
public String depthFirstSearch(int v) { if (v < 0 || v >= numOfVexs) throw new ArrayIndexOutOfBoundsException(); visited = new boolean[numOfVexs]; StringBuilder sb = new StringBuilder(); Stack<Integer> stack = new Stack<Integer>(); stack.push(v); visited[v] = true; while (!stack.isEmpty()) { v = stack.pop(); sb.append(vexs[v] + ","); for (int i = numOfVexs - 1; i >= 0; i--) { if ((edges[v][i] != 0 && edges[v][i] != Integer.MAX_VALUE) && !visited[i]) { stack.push(i); visited[i] = true; } } } return sb.length() > 0 ? sb.substring(0, sb.length() - 1) : null; }
基於鄰接表的演算法實現:
public String depthFirstSearch(int v) { if (v < 0 || v >= numOfVexs) throw new ArrayIndexOutOfBoundsException(); visited = new boolean[numOfVexs]; StringBuilder sb = new StringBuilder(); Stack<Integer> stack = new Stack<Integer>(); stack.push(v); visited[v] = true; ENode current; while (!stack.isEmpty()) { v = stack.pop(); sb.append(vexs[v].data + ","); current = vexs[v].firstadj; while (current != null) { if (!visited[current.adjvex]) { stack.push(current.adjvex); visited[current.adjvex] = true; } current = current.nextadj; } } return sb.length() > 0 ? sb.substring(0, sb.length() - 1) : null; }
廣度優先搜尋演算法
演算法的思想
從圖中的某一個頂點x出發,訪問x,然後訪問與x所相鄰的所有未被訪問的頂點x1、x2……xn,接著再依次訪問與x1、x2……xn相鄰的未被訪問的所有頂點。依次類推,直至圖中的每個頂點都被訪問。
演算法實現的思想
廣度優先遍歷背後基於佇列,下面介紹一下具體實現的方法:
- 訪問起始頂點,並將插入佇列;
- 從佇列中刪除隊頭頂點,將與其相鄰的未被訪問的頂點插入佇列中;
- 重複第二步,直至佇列為空。
未被訪問的頂點怎麼識別呢?利用visited陣列來進行標記。
演算法的實現
基於鄰接矩陣的演算法實現:
public String breadFirstSearch(int v) {
if (v < 0 || v >= numOfVexs)
throw new ArrayIndexOutOfBoundsException();
visited = new boolean[numOfVexs];
StringBuilder sb = new StringBuilder();
Queue<Integer> queue = new LinkedList<Integer>();
queue.offer(v);
visited[v] = true;
while (!queue.isEmpty()) {
v = queue.poll();
sb.append(vexs[v] + ",");
for (int i = 0; i < numOfVexs; i++) {
if ((edges[v][i] != 0 && edges[v][i] != Integer.MAX_VALUE)
&& !visited[i]) {
queue.offer(i);
visited[i] = true;
}
}
}
return sb.length() > 0 ? sb.substring(0, sb.length() - 1) : null;
}
基於鄰接表的演算法實現:
public String breadFirstSearch(int v) {
if (v < 0 || v >= numOfVexs)
throw new ArrayIndexOutOfBoundsException();
visited = new boolean[numOfVexs];
StringBuilder sb = new StringBuilder();
Queue<Integer> queue = new LinkedList<Integer>();
queue.offer(v);
visited[v] = true;
ENode current;
while (!queue.isEmpty()) {
v = queue.poll();
sb.append(vexs[v].data + ",");
current = vexs[v].firstadj;
while (current != null) {
if (!visited[current.adjvex]) {
queue.offer(current.adjvex);
visited[current.adjvex] = true;
}
current = current.nextadj;
}
}
return sb.length() > 0 ? sb.substring(0, sb.length() - 1) : null;
}
這邊的其他的主要部分(如成員變數的定義等),參考【資料結構】圖(鄰接矩陣、鄰接表)的JAVA程式碼實現。