詳解BFS和DFS及Java實現

1.圖的表示

圖是由頂點和邊組成,圖最常用的兩種方法就是鄰接表和鄰接矩陣。這兩種辦法分別用表和矩陣的方式描述圖中各頂點之間的聯系。

下面分別展示了兩種表示上面這個圖的方法:

2.圖的遍歷

廣度優先遍歷和深度優先遍歷是遍歷圖的兩種最常用的方法,下面將詳細進行介紹。

2.1 廣度優先遍歷(BFS)

即Breadth First Search,其主要思想是從起始點開始,將其鄰近的所有頂點都加到一個隊列(FIFO)中去,然后標記下這些頂點離起始頂點的距離為1.最后將起始頂點標記為已訪問,今后就不會再訪問。然后再從隊列中取出最先進隊的頂點A,也取出其周邊鄰近節點,加入隊列末尾,將這些頂點的距離相對A再加1,最后離開這個頂點A。依次下去,直到隊列為空為止。從上面描述的過程我們知道每個頂點被訪問的次數最多一次(已訪問的節點不會再訪問),而對于連通圖來說,每個頂點都會被訪問。加上每個頂點的鄰接鏈表都會被遍歷,因此BFS的時間復雜度是Θ(V+E),其中V是頂點個數,E是邊數,也就是所有鄰接表中的元素個數。為了更好的說明這個過程,下圖列出了對一個圖的BFS的過程。

代碼實現:

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

public class BFSDemo {
    public static void main(String[] args) {
        
        //構造各頂點
        LinkedList<Character> list_s = new LinkedList<Character>();
        list_s.add('w');
        list_s.add('r');
        LinkedList<Character> list_w = new LinkedList<Character>();
        list_w.add('s');
        list_w.add('i');
        list_w.add('x');
        LinkedList<Character> list_r = new LinkedList<Character>();
        list_r.add('s');
        list_r.add('v');
        LinkedList<Character> list_x = new LinkedList<Character>();
        list_x.add('w');
        list_x.add('i');
        list_x.add('u');
        list_x.add('y');
        LinkedList<Character> list_v = new LinkedList<Character>();
        list_v.add('r');
        LinkedList<Character> list_i = new LinkedList<Character>();
        list_i.add('u');
        list_i.add('x');
        list_i.add('w');
        LinkedList<Character> list_u = new LinkedList<Character>();
        list_u.add('i');
        list_u.add('x');
        list_u.add('y');
        LinkedList<Character> list_y = new LinkedList<Character>();
        list_y.add('u');
        list_y.add('x');
        
        //構造圖
        HashMap<Character, LinkedList<Character>> graph = new HashMap<Character, LinkedList<Character>>();
        graph.put('s', list_s);
        graph.put('w', list_w);
        graph.put('r', list_r);
        graph.put('x', list_x);
        graph.put('v', list_v);
        graph.put('i', list_i);
        graph.put('y', list_y);
        graph.put('u', list_u);
        //記錄每個頂點離起始點的距離,也即最短距離
        HashMap<Character, Integer> dist = new HashMap<Character, Integer>();
        //遍歷的起始點
        char start = 's';
        //調用廣度優先方法
        bfs(graph, dist, start);
    }
    
    private static void bfs(HashMap<Character, LinkedList<Character>> graph, HashMap<Character, Integer> dist,
            char start) {
        Queue<Character> q = new LinkedList<>();
        q.add(start);// 將s作為起始頂點加入隊列
        dist.put(start, 0);
        int i = 0;
        while (!q.isEmpty()) {
            char top = q.poll();// 取出隊首元素
            i++;
            System.out.println("The " + i + "th element:" + top + " Distance from s is:" + dist.get(top));
            int d = dist.get(top) + 1;// 得出其周邊還未被訪問的節點的距離
            for (Character c : graph.get(top)) {
                if (!dist.containsKey(c))// 如果dist中還沒有該元素說明還沒有被訪問
                {
                    dist.put(c, d);
                    q.add(c);
                }
            }
        }
    }

}

運行結果:

The 1th element:s Distance from s is:0
The 2th element:w Distance from s is:1
The 3th element:r Distance from s is:1
The 4th element:i Distance from s is:2
The 5th element:x Distance from s is:2
The 6th element:v Distance from s is:2
The 7th element:u Distance from s is:3
The 8th element:y Distance from s is:3

2.2 深度優先遍歷(DFS)

即Depth First Search,深度優先搜索是從起始頂點開始,遞歸訪問其所有鄰近節點,比如A節點是其第一個鄰近節點,而B節點又是A的一個鄰近節點,則DFS訪問A節點后再訪問B節點,如果B節點有未訪問的鄰近節點的話將繼續訪問其鄰近節點,否則繼續訪問A的未訪問鄰近節點,當所有從A節點出去的路徑都訪問完之后,繼續遞歸訪問除A以外未被訪問的鄰近節點。具體看下圖:

代碼如下:

import java.util.HashMap;
import java.util.LinkedList;

public class DFSDemo {
    public static void main(String[] args) {
        //構造各頂點
        LinkedList<Character> list_u = new LinkedList<Character>();
        list_u.add('v');
        list_u.add('x');
        LinkedList<Character> list_v = new LinkedList<Character>();
        list_v.add('y');
        LinkedList<Character> list_y = new LinkedList<Character>();
        list_y.add('x');
        LinkedList<Character> list_x = new LinkedList<Character>();
        list_x.add('v');
        LinkedList<Character> list_w = new LinkedList<Character>();
        list_w.add('y');
        list_w.add('z');
        LinkedList<Character> list_z = new LinkedList<Character>();
        //構造圖
        HashMap<Character, LinkedList<Character>> graph = new HashMap<Character, LinkedList<Character>>();
        graph.put('u', list_u);
        graph.put('v', list_v);
        graph.put('y', list_y);
        graph.put('x', list_x);
        graph.put('w', list_w);
        graph.put('z', list_z);
        
        HashMap<Character, Boolean> visited = new HashMap<Character, Boolean>();
        //調用深度優先遍歷方法
        dfs(graph, visited);
    }
    
    private static void dfs(HashMap<Character, LinkedList<Character>> graph, HashMap<Character, Boolean> visited) {
        visit(graph, visited, 'u');// 為了和圖中的順序一樣,我認為控制了DFS先訪問u節點
        visit(graph, visited, 'w');
    }

    //通過一個全局變量count記錄了進入每個節點和離開每個節點的時間
    static int count;
    private static void visit(HashMap<Character, LinkedList<Character>> graph, HashMap<Character, Boolean> visited,
            char start) {
        if (!visited.containsKey(start)) {
            count++;
            System.out.println("The time into element " + start + ":" + count);// 記錄進入該節點的時間
            visited.put(start, true);
            for (char c : graph.get(start)) {
                if (!visited.containsKey(c)) {
                    visit(graph, visited, c);// 遞歸訪問其鄰近節點
                }
            }
            count++;
            System.out.println("The time out element " + start + ":" + count);// 記錄離開該節點的時間
        }
    }

}

運行結果:

The time into element u:1
The time into element v:2
The time into element y:3
The time into element x:4
The time out element x:5
The time out element y:6
The time out element v:7
The time out element u:8
The time into element w:9
The time into element z:10
The time out element z:11
The time out element w:12
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容