安琪拉教魯班學算法之BFS和DFS
《安琪拉與面試官二三事》系列文章
一個HashMap能跟面試官扯上半個小時
一個synchronized跟面試官扯了半個小時《安琪拉教魯班學算法》系列文章
BFS 和 DFS在算法中屬於有舉足輕重的地位,本文希望通過使用王者峽谷二位脆皮英雄對話的方式講解動態規劃,讓大家在輕鬆愉快的氛圍中搞懂BFS 和 DFS。
魯班: 安琪拉,你知道 BFS 和DFS 嗎?
安琪拉:當然知道啊,BFS 全程是 廣度優先搜索, DFS 指的是深度優先搜索。
魯班: 安琪拉妹妹,你這麼說我還是很蒙,能跟我詳細講講嗎?
安琪拉:魯班哥哥,看你求知慾這麼強,咱倆又都是脆皮的份上,我給你講講BFS 和 DFS。
以下圖爲例,
廣度優先搜索 和 深度優先搜索都是遍歷圖/樹 節點的方式
廣度優先搜索: 如下圖所示,廣度優先搜索,例如從上圖中選取一個節點A,作爲起點,寬度優先搜索,遍歷的方式是遍歷A、 和A相連的B和C,和B相連的D,和C相連的E,和D相連的F,以這樣的順序訪問圖中的節點。
深度優先搜索:還是以A作爲起點,一直走到底,直到不能訪問,再回退,A => B => D => F =>E => C
代碼實現例子:
public static void main(String[] args) {
//以map 存儲圖中節點的關係 A 相連的節點爲 B、C
//就可表示爲 List<Character> aList = new LinkedList<>(Arrays.asList('B','C'));
Map<Character, List<Character>> graph = buildGraph();
dfs(graph, 'A');
bfs(graph, 'A');
}
// 構造圖
private static Map<Character,List<Character>> buildGraph(){
Map<Character, List<Character>> graph = new HashMap<>();
List<Character> aList = new LinkedList<>(Arrays.asList('B','C'));
List<Character> bList = new LinkedList<>(Arrays.asList('A','C','D'));
List<Character> cList = new LinkedList<>(Arrays.asList('A','B','D','E'));
List<Character> dList = new LinkedList<>(Arrays.asList('B','F','E','C'));
List<Character> eList = new LinkedList<>(Arrays.asList('C','D'));
List<Character> fList = new LinkedList<>(Arrays.asList('D'));
graph.put('A',aList);
graph.put('B',bList);
graph.put('C',cList);
graph.put('D',dList);
graph.put('E',eList);
graph.put('F',fList);
return graph;
}
/**
* 深度優先搜索 關鍵是使用棧來維護相鄰後繼節點
* @param graph 要遍歷的圖
* @param s 起始點
*/
public static void dfs(Map<Character,List<Character>> graph, Character s){
//走過的節點
Set<Character> visited = new HashSet<>();
Stack<Character> stack = new Stack<>();
stack.push(s);
while(!stack.empty()){
Character accessC = stack.pop();
if(!visited.contains(accessC)){
//訪問函數
System.out.print("->"+accessC);
visited.add(accessC);
}
graph.get(accessC).forEach(c ->{
if(!visited.contains(c)){
stack.push(c);
}
});
}
}
/**
* 廣度優先搜索 使用隊列維護相鄰後續節點
* @param graph
* @param s
*/
public static void bfs(Map<Character,List<Character>> graph, Character s){
//走過的節點
Set<Character> visited = new HashSet<>();
Queue<Character> queue = new LinkedList<>();
queue.offer(s);
while (!queue.isEmpty()){
Character accessC = queue.poll();
if(!visited.contains(accessC)){
//訪問函數
System.out.print("->"+accessC);
visited.add(accessC);
}
graph.get(accessC).forEach(c ->{
if(!visited.contains(c)){
queue.offer(c);
}
});
}
}
歡迎大家關注 Wx公衆號:安琪拉的博客 獲取更多技術資料