1. 程式人生 > >JAVA實現圖的廣度優先遍歷

JAVA實現圖的廣度優先遍歷

一:廣度優先遍歷介紹.

      廣度優先遍歷(BFS),廣度優先遍歷是儘可能的更多的把相鄰的元素都遍歷了,然後在訪問外層的,有點像中心開花由內到外.

     從圖中任選一個頂點v,作為起始頂點.例如下圖:BFS的遍歷順序是首先是V,然後是W1,W2,Y11,Y12,Y21,Y22.總是第一層訪問完了,才訪問第二層的,這就是二叉樹的層序訪問嘛.

 

 

二:廣度優先遍歷的實現.使用佇列實現.

BFS的遍歷序列如下:沒有確定起始點就不唯一.這裡是A是起點.

import java.util.LinkedList;
import java.util.Queue;
/**
 * title: com.lx.algorithm.graph
 * @author: lixing
 * date: 2018/10/31 17:57
 * description:廣度優先遍歷使用佇列實現,(無向非連通圖)非遞迴實現.
 */
public class BFSTest {

    /**
     * 儲存節點資訊
     */
    private char[] vertices;

    /**
     * 儲存邊資訊(鄰接矩陣)
     */
    private int[][] arcs;

    /**
     * 圖的節點數
     */
    private int vexnum;

    /**
     * 記錄節點是否已被遍歷
     */
    private boolean[] visited;

    /**
     * 初始化
     */
    public BFSTest(int n) {
        vexnum = n;
        vertices = new char[n];
        arcs = new int[n][n];
        visited = new boolean[n];
        for (int i = 0; i < vexnum; i++) {
            for (int j = 0; j < vexnum; j++) {
                arcs[i][j] = 0;
            }
        }
    }

    /**
     * 新增邊
     */
    public void addEdge(int i, int j) {
        if (i == j) {
            return;
        }
        arcs[i][j] = 1;
        arcs[j][i] = 1;
    }

    /**
     * 設定節點集
     */
    public void setVertices(char[] vertices) {
        this.vertices = vertices;
    }

    /**
     * 設定節點訪問標記
     */
    public void setVisited(boolean[] visited) {
        this.visited = visited;
    }

    /**
     * 列印遍歷節點
     */
    public void visit(int i) {
        System.out.print(vertices[i] + " ");
    }

    /**
     *  輸出鄰接矩陣
     */
    public void pritf(int[][] arcs){
        for(int i=0;i<arcs.length;i++){
            for(int j=0;j<arcs[0].length;j++){
                System.out.print(arcs[i][j]+ "\t");
            }
            System.out.println();
        }
    }

    /**
     * 實現廣度優先遍歷
     */
    public void bfs() {
        // 初始化所有的節點的訪問標誌
        for (int v = 0; v < visited.length; v++) {
            visited[v] = false;
        }
        Queue<Integer> queue = new LinkedList<Integer>();
        for (int i = 0; i < vexnum; i++) {
            if (visited[i] == false) {
                visited[i] = true;
                // 列印當前已經遍歷的節點
                visit(i);
                // 新增到佇列裡面
                queue.add(i);
                // 只要佇列不為空
                while (!queue.isEmpty()) {
                    // 出隊節點,也就是這一層的節點.
                    int k = queue.poll();
                    // 遍歷所有未被訪問的鄰接節點,放入佇列
                    for (int j = 0; j < vexnum; j++) {
                        // 也就是訪問這一層剩下的未被訪問的節點
                        if (arcs[k][j] == 1 && visited[j] == false) {
                            visited[j] = true;
                            visit(j);
                            queue.add(j);
                        }
                    }
                }
            }
        }
        System.out.println();
        pritf(arcs);
    }

    public static void main(String[] args) {
        BFSTest g = new BFSTest(9);
        char[] vertices = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'};
        // 設定頂點集
        g.setVertices(vertices);
        // 新增邊
        g.addEdge(0, 1);
        g.addEdge(0, 5);
        g.addEdge(1, 0);
        g.addEdge(1, 2);
        g.addEdge(1, 6);
        g.addEdge(1, 8);
        g.addEdge(2, 1);
        g.addEdge(2, 3);
        g.addEdge(2, 8);
        g.addEdge(3, 2);
        g.addEdge(3, 4);
        g.addEdge(3, 6);
        g.addEdge(3, 7);
        g.addEdge(3, 8);
        g.addEdge(4, 3);
        g.addEdge(4, 5);
        g.addEdge(4, 7);
        g.addEdge(5, 0);
        g.addEdge(5, 4);
        g.addEdge(5, 6);
        g.addEdge(6, 1);
        g.addEdge(6, 3);
        g.addEdge(6, 5);
        g.addEdge(6, 7);
        g.addEdge(7, 3);
        g.addEdge(7, 4);
        g.addEdge(7, 6);
        g.addEdge(8, 1);
        g.addEdge(8, 2);
        g.addEdge(8, 3);
        System.out.print("廣度優先遍歷(佇列):");
        g.bfs();
    }
}

 執行結果:

三:深度優先對比廣度優先遍歷.

    1. 兩種演算法的時間複雜度都是一樣的.

    2. 深度優先遍歷涉及的輔助資料結構是棧,廣度優先遍歷涉及的佇列.

    3. 廣度優先遍歷佔用的記憶體比較多是橫向元素入隊的,如果這一層元素比較多,那麼隊內的元素就比較多,而深度優先遍歷的棧內元素是深入棧的,每一條路徑不會儲存太對的元素,棧內元素依次出棧,佔用記憶體減少.