算法十——深度优先搜索和广度优先搜索
文章出處:極客時間《數據結構和算法之美》-作者:王爭。該系列文章是本人的學習筆記。
搜索算法
算法是作用于數據結構之上的。深度優先搜索、廣度優先搜索是作用于圖這種數據結構之上的。圖上的搜索算法可以理解為從一個頂點到另外一個頂點。
常用的搜索算法有:暴力的深度優先搜索、廣度優先搜索,還有A*、IDA*等啟發式搜索。
實際應用舉例
在社交網絡中有六度分隔理論,就是一個人最多通過六個人可以認識另外一個人。一個用戶的一度好友就是他的好友,二度好友是他好友的好友,以此類推。給你一個關系圖,你可以找到一個用戶的三度好友嗎?
廣度優先搜索(BFS)
BFS:先找離起始頂點最近的點,然后是次近,依次向外搜索。
下面的代碼是無向圖的BFS代碼。
/*** 無向圖*/ public class UnDirectedGraph {private int v;//頂點個數private LinkedList<Integer> adj[];//鄰接表public UnDirectedGraph(int v){this.v = v;this.adj = new LinkedList[v];for(int i=0;i<v;i++){this.adj[i] = new LinkedList<>();}}public void addEdge(int s,int t){this.adj[s].add(t);this.adj[t].add(s);}/*** 廣度優先搜索從s節點到t節點:打印從s到t的節點路徑* @param s* @param t*/public void bfs(int s, int t) {if(s==t){System.out.println(s);return;}Queue<Integer> queue = new LinkedList<>();queue.offer(s);boolean[] visited = new boolean[this.v];visited[s] = true;int[] pre = new int[v];Arrays.fill(pre,-1);while(!queue.isEmpty()){int size = queue.size();for(int i =0;i<size;i++){//每一層int w = queue.poll();for(int j =0;j<this.adj[w].size();j++){int q = this.adj[w].get(j);if(!visited[q]){pre[q] = w;if(q==t){printPath(pre,s,t);return;}visited[q]=true;queue.offer(q);}}}}}private void printPath(int[] pre,int s,int t) {if(s!=t && pre[t]!=-1){printPath(pre,s,pre[t]);}System.out.print(t+"\t");} }這里三個重要的臨時變量queue、visited、pre。
queue:是一個隊列,存儲已經被訪問,但是鄰接點還沒有被訪問的節點。
visited:記錄已經訪問過的節點,防止重復訪問。
pre:記錄從哪個節點可以達到下標所表示的節點。pre[w]記錄從哪個節點達到w節點 。
時間復雜度分析:BFS中每個節點都會被訪問一次,入隊一次,每條邊都會被訪問一次,時間復雜度O(V+E)。V表示頂點個數,E表示邊的個數。
空間復雜度分析:臨時變量queue、visited、pre的個數都不會超過頂點個數。所以上O(V)。
上面的代碼可以抽象出BFS代碼的框架。
深度優先搜索(DFS)
DFS:DFS是從起始頂點開始,按照一條路徑一直走到終點t或者不能再走下去。然后返回到上一個可選擇的狀態,選擇另外一條路徑,繼續走。DFS是一種非常有名的算法思想:回溯。
下圖中實現代表搜索路徑,虛線代表回退。
private boolean found = false;public void dfs(int s, int t) {boolean[] visited = new boolean[this.v];int[] pre = new int[v];Arrays.fill(pre,-1);dfs(s,t,visited,pre);printPath(pre,s,t);}private void dfs(int w, int t, boolean[] visited, int[] pre) {if(w==t){found = true;return;}visited[w] = true;if(!found){for(int j =0;j<this.adj[w].size() && !found;j++){int q = this.adj[w].get(j);if(!visited[q]) {pre[q] = w;visited[q]=true;dfs(q,t,visited,pre);}}}}時間復雜度分析:從圖中看每條邊最多被訪問2次,一次搜索,一次回退。時間復雜度O(E)。
空間復雜度分析:消耗內存主要是 visited、prev 數組和遞歸調用棧。visited、prev 數組和頂點個數相同。遞歸調用不會超過頂點的個數。所以空間復雜度O(V)。
適用范圍
DFS和BFS搜索的空間復雜度都是O(V),當頂點個數很大的時候,就不適合這兩種算法。
三度好友
上面提到的查找一個人的三度好友適合用BFS。一層一層向外搜索。找到第三層。
總結
以上是生活随笔為你收集整理的算法十——深度优先搜索和广度优先搜索的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 从Java程序员到架构师,从工程师到技术
- 下一篇: DBCP|C3P0参数详解