1. 程式人生 > >圖的廣度優先遍歷演算法

圖的廣度優先遍歷演算法

前言

廣度優先遍歷演算法是圖的另一種基本遍歷演算法,其基本思想是盡最大程度輻射能夠覆蓋的節點,並對其進行訪問。以迷宮為例,深度優先搜尋更像是一個人在走迷宮,遇到沒有走過就標記,遇到走過就退一步重新走;而廣度優先搜尋則可以想象成一組人一起朝不同的方向走迷宮,當出現新的未走過的路的時候,可以理解成一個人有分身術,繼續從不同的方向走,,當相遇的時候則是合二為一(好吧,有點扯了)。

廣度優先遍歷演算法的遍歷過程

圖

仍然以上一篇圖的深度優先遍歷演算法的例子進行說明,下面是廣度優先遍歷的具體過程:

  1. 從起點0開始遍歷
  2. 從其鄰接表得到所有的鄰接節點,把這三個節點都進行標記,表示已經訪問過了
  3. 從0的鄰接表的第一個頂點2開始尋找新的叉路
  4. 查詢頂點2的鄰接表,並將其所有的鄰接節點都標記為已訪問
  5. 繼續從頂點0的鄰接表的第二個節點,也就是頂點1,遍歷從頂點1開始
  6. 查詢頂點1的鄰接表的所有鄰接節點,也就是頂點0和頂點2,發現這兩個頂點都被訪問過了,頂點1返回
  7. 從頂點0的下一個鄰接節點,也就是頂點5,開始遍歷
  8. 查詢頂點5的鄰接節點,發現其鄰接節點3和0都被訪問過了,頂點5返回
  9. 繼續從2的下一個鄰接節點3開始遍歷
  10. 尋找頂點3的鄰接節點,發現都被訪問過了,頂點3返回
  11. 繼續尋找頂點2的下一個鄰接節點4,發現4的所有鄰接節點都被訪問過了,頂點4返回
  12. 頂點2的所有鄰接節點都放過了,頂點2返回,遍歷結束

廣度優先遍歷演算法的實現

與深度優先遍歷演算法相同,都需要一個標記陣列來記錄一個節點是否被訪問過,在深度優先遍歷演算法中,使用的是一個棧來實現的,但是廣度優先因為需要記錄與起點距離最短的節點,或者說能夠用盡可能少的邊連通的節點,距離短的優先遍歷,距離遠的後面再遍歷,更像是佇列。所以在廣度優先遍歷演算法中,需要使用佇列來實現這個過程。下面是具體的實現程式碼(已附詳細註釋):

package com.rhwayfun.algorithm.graph;

import java.util.LinkedList;
import java.util.Queue;

/**
 * 廣度優先搜尋
 * <p>Title:BreadFirstSearch</p>
 * <p>Description:</p>
 * @author rhwayfun
 * @date Dec 23, 2015 4:43:41 PM
 * @version 1.0
 */
public class BreadFirstSearch {

    //建立一個標記陣列
private boolean[] marked; //起點 private int s; public BreadFirstSearch(MyGraph G, int s){ marked = new boolean[G.V()]; this.s = s; //開始廣度優先搜尋 bfs(G,s); } private void bfs(MyGraph G, int s2) { //建立一個佇列 Queue<Integer> queue = new LinkedList<Integer>(); //標記起點 marked[s] = true; queue.add(s); System.out.print(s + " "); while(!queue.isEmpty()){ //從佇列中刪除下一個節點 int v = queue.poll(); //將該節點的所有鄰接節點加入佇列中 for(int w : G.adj(v)){ //如果沒有標記就標記 if(!marked[w]){ marked[w] = true; System.out.print(w + " "); queue.add(w); } } } } }

執行該程式,發現廣度優先遍歷演算法對上圖的遍歷順序是0,2,1,5,3,4。