"《算法導論》之‘圖’":深度優先搜索、寬度優先搜索(無向圖、有向圖)

  本文兼參考自《算法導論》及《算法》。java

  之前一直不可以理解深度優先搜索和廣度優先搜索,老是很怕去碰它們,但通過閱讀上邊提到的兩本書,豁然開朗,立刻就能理解得更進一步。git

  下文將會用到的一個無向圖例子以下:github

  

深度優先搜索

迷宮搜索

  在《算法》這本書中,做者寫了很好的一個故事。這個故事讓我立刻理解了深度優先搜索的思想。算法

  以下圖1-1所示,如何在這個迷宮中找到出路呢?方法見圖1-2.ide

  

  圖1-1 等價的迷宮模型this

 

  探索迷宮而不迷路的一種古老辦法(至少能夠追溯到忒修斯和米諾陶的傳說)叫作Tremaux搜索,以下圖所示。要探索迷宮中的全部通道,咱們須要:spa

  1)選擇一條沒有標記過的通道,在你走過的路上鋪一條繩子;code

  2)標記全部你第一次路過的路口和通道;blog

  3)當來到一個標記過的路口時,用繩子回退到上個路口;rem

  4)當回退到的路口已沒有可走的通道時繼續回退。

  繩子能夠保證你總能找到一條出路,標記則能保證你不會兩次通過同一條通道或同一個路口。

  

  圖1-2 Tremaux探索

深度優先搜索

  《算法》做者給出的Java代碼以下:

 1 public class DepthFirstSearch
 2 {
 3     private boolean[] marked;
 4     private int count;
 5     
 6     public DepthFirstSearch(Graph G, int s)
 7     {
 8         marked = new boolean[G.V()];
 9         dfs(G, s);
10     }
11     
12     private void dfs(Graph G, int v)
13     {
14         marked[v] = true;
15         count++;
16         for(int w : G.adj(v))
17         {
18             if(!marked[w])
19             {
20                 dfs(G, w);
21             }
22         }
23     }
24     
25     public boolean marked(int w)
26     {
27         return marked[w];
28     }
29     
30     public int count()
31     {
32         return count;
33     }
34 }
DFS.java

  具體例子以下圖1-3:

  

  圖1-3 使用深度優先探索的軌跡,尋找全部和頂點0連通的頂點

尋找路徑

   《算法》做者給出的Java代碼以下:

 1 public class DepthFirstPaths
 2 {
 3     private boolean[] marked; // Has dfs() been called for this vertex?
 4     private int[] edgeTo; // last vertex on known path to this vertex
 5     private final int s; // source
 6     public DepthFirstPaths(Graph G, int s)
 7     {
 8         marked = new boolean[G.V()];
 9         edgeTo = new int[G.V()];
10         this.s = s;
11         dfs(G, s);
12     }
13     
14     private void dfs(Graph G, int v)
15     {
16         marked[v] = true;
17         for (int w : G.adj(v))
18             if (!marked[w])
19             {
20                 edgeTo[w] = v;
21                 dfs(G, w);
22             }
23     }
24     
25     public boolean hasPathTo(int v)
26     { 
27         return marked[v]; 
28     }
29     
30     public Iterable<Integer> pathTo(int v)
31     {
32         if (!hasPathTo(v)) return null;
33         Stack<Integer> path = new Stack<Integer>();
34         for (int x = v; x != s; x = edgeTo[x])
35             path.push(x);
36         path.push(s);
37         return path;
38     }
39 }
DFS.java

  

  圖1-4 pathTo(5)的計算軌跡

  

  圖1-5 使用深度優先搜索的軌跡,尋找全部起點爲0的路徑

廣度優先搜索

迷宮搜索

    深度優先搜索就好像是一我的在走迷宮,廣度優先搜索則好像是一組人在一塊兒朝各個方向走這座迷宮,每一個人都有本身的繩子。當出現新的叉路時,能夠假設一個探索者能夠分裂爲更多的人來搜索它們。當兩個探索者相遇時,會合二爲一(並繼續使用先到達者的繩子)。以下圖2-1:

  

  圖2-1 廣度優先的迷宮搜索

廣度優先搜索

  《算法》做者給出的使用廣度優先搜索查找圖中的路徑的Java代碼以下:

 1 public class BreadthFirstPaths
 2 {
 3     private boolean[] marked;     // Is a shortest path to this vertex known?
 4     private int[] edgeTo;         // last vertex on known path to this vertex
 5     private final int s;         // source
 6     
 7     public BreadthFirstPaths(Graph G, int s)
 8     {
 9         marked = new boolean[G.V()];
10         edgeTo = new int[G.V()];
11         this.s = s;
12         bfs(G, s);
13     }
14     
15     private void bfs(Graph G, int s)
16     {
17         Queue<Integer> queue = new Queue<Integer>();
18         marked[s] = true;     // Mark the source
19         queue.enqueue(s);     // and put it on the queue.
20         while (!q.isEmpty())
21         {
22             int v = queue.dequeue();     // Remove next vertex from the queue.
23             for (int w : G.adj(v))
24             if (!marked[w])             // For every unmarked adjacent vertex,
25             {
26                 edgeTo[w] = v;             // save last edge on a shortest path,
27                 marked[w] = true;         // mark it because path is known,
28                 queue.enqueue(w);         // and add it to the queue.
29             }
30         }
31     }
32     
33     public boolean hasPathTo(int v)
34     { 
35         return marked[v]; 
36     }
37     
38     public Iterable<Integer> pathTo(int v)
39     // Same as for DFS.
40 }
BFS.java

  一個例子以下:

  

  圖2-2 使用廣度優先搜索尋找全部起點爲0的路徑的結果

  

  圖2-3 使用廣度優先搜索的軌跡,尋找全部起點爲0的路徑

 

  具體代碼已經託管到Github.

相關文章
相關標籤/搜索