漫畫:深度優先遍歷和廣度優先遍歷

640?wx_fmt=gif

640?wx_fmt=jpeg640?wx_fmt=jpeg

 

 

—————  第二天  —————

 

 

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

 

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

————————————

640?wx_fmt=jpeg

640?wx_fmt=jpeg

 

640?wx_fmt=jpeg

 

640?wx_fmt=jpeg

 

 

什麼是 深度/廣度 優先遍歷?

深度優先遍歷簡稱DFS(Depth First Search),廣度優先遍歷簡稱BFS(Breadth First Search),它們是遍歷圖當中所有頂點的兩種方式。

這兩種遍歷方式有什麼不同呢?我們來舉個栗子:

我們來到一個遊樂場,遊樂場裏有11個景點。我們從景點0開始,要玩遍遊樂場的所有景點,可以有什麼樣的遊玩次序呢?

 

640?wx_fmt=png

第一種是一頭扎到底的玩法。我們選擇一條支路,儘可能不斷地深入,如果遇到死路就往回退,回退過程中如果遇到沒探索過的支路,就進入該支路繼續深入。

在圖中,我們首先選擇景點1的這條路,繼續深入到景點7、景點8,終於發現走不動了(景點旁邊的數字代表探索次序):

640?wx_fmt=png

於是,我們退回到景點7,然後探索景點10,又走到了死衚衕。於是,退回到景點1,探索景點9:

640?wx_fmt=png

按照這個思路,我們再退回到景點0,後續依次探索景點2、3、5、4、6,終於玩遍了整個遊樂場:

640?wx_fmt=png

像這樣先深入探索,走到頭再回退尋找其他出路的遍歷方式,就叫做深度優先遍歷(DFS)

640?wx_fmt=jpeg

640?wx_fmt=jpeg

除了像深度優先遍歷這樣一頭扎到底的玩法以外,我們還有另一種玩法:首先把起點相鄰的幾個景點玩遍,然後去玩距離起點稍遠一些(隔一層)的景點,然後再去玩距離起點更遠一些(隔兩層)的景點......

在圖中,我們首先探索景點0的相鄰景點1、2、3、4:

 

640?wx_fmt=png

接着,我們探索與景點0相隔一層的景點7、9、5、6:

 

640?wx_fmt=png

最後,我們探索與景點0相隔兩層的景點8、10:

 

640?wx_fmt=png

像這樣一層一層由內而外的遍歷方式,就叫做廣度優先遍歷(BFS)

640?wx_fmt=jpeg

640?wx_fmt=jpeg

 

深度/廣度優先遍歷 的實現

640?wx_fmt=jpeg

 

640?wx_fmt=jpeg

深度優先遍歷

首先說說深度優先遍歷的實現過程。這裏所說的回溯是什麼意思呢?回溯顧名思義,就是自後向前,追溯曾經走過的路徑。

我們把剛纔遊樂場的例子抽象成數據結構的圖,假如我們依次訪問了頂點0、1、7、8,發現無路可走了,這時候我們要從頂點8退回到頂點7。

640?wx_fmt=png

而後我們探索了頂點10,又無路可走了,這時候我們要從頂點10退回到頂點7,再退回到頂點1。

 

640?wx_fmt=png

像這樣的自後向前追溯曾經訪問過的路徑,就叫做回溯。

要想實現回溯,可以利用棧的先入後出特性,也可以採用遞歸的方式(因爲遞歸本身就是基於方法調用棧來實現)。

下面我們來演示一下具體實現過程。

首先訪問頂點0、1、7、8,這四個頂點依次入棧,此時頂點8是棧頂:

640?wx_fmt=png

從頂點8退回到頂點7,頂點8出棧:

640?wx_fmt=png

接下來訪問頂點10,頂點10入棧:

640?wx_fmt=png

從頂點10退到頂點7,從頂點7退到頂點1,頂點10和頂點7出棧:

 

640?wx_fmt=png

探索頂點9,頂點9入棧:

640?wx_fmt=png

以此類推,利用這樣一個臨時棧來實現回溯,最終遍歷完所有頂點。

廣度優先遍歷

接下來該說說廣度優先遍歷的實現過程了。剛纔所說的重放是什麼意思呢?似乎聽起來和回溯差不多?其實,回溯與重放是完全相反的過程。

仍然以剛纔的圖爲例,按照廣度優先遍歷的思想,我們首先遍歷頂點0,然後遍歷了鄰近頂點1、2、3、4:

640?wx_fmt=png

接下來我們要遍歷更外圍的頂點,可是如何找到這些更外圍的頂點呢?我們需要把剛纔遍歷過的頂點1、2、3、4按順序重新回顧一遍,從頂點1發現鄰近的頂點7、9;從頂點3發現鄰近的頂點5、6。

640?wx_fmt=png

像這樣把遍歷過的頂點按照之前的遍歷順序重新回顧,就叫做重放。同樣的,要實現重放也需要額外的存儲空間,可以利用隊列的先入先出特性來實現。

下面我們來演示一下具體實現過程。

首先遍歷起點頂點0,頂點0入隊:

640?wx_fmt=png

接下來頂點0出隊,遍歷頂點0的鄰近頂點1、2、3、4,並且把它們入隊:

640?wx_fmt=png

然後頂點1出隊,遍歷頂點1的鄰近頂點7、9,並且把它們入隊:

640?wx_fmt=png

然後頂點2出隊,沒有新的頂點可入隊:

640?wx_fmt=png

以此類推,利用這樣一個隊列來實現重放,最終遍歷完所有頂點。

640?wx_fmt=jpeg

640?wx_fmt=jpeg

 

640?wx_fmt=jpeg

 
  •  
  1. /**
  2. 圖的頂點
  3. / private static class Vertex { int data; Vertex(int data) { this.data = data; } } /*
  4. 圖(鄰接表形式)
  5. / private static class Graph { private int size; private Vertex[] vertexes; private LinkedList adj[]; Graph(int size){ this.size = size; //初始化頂點和鄰接矩陣 vertexes = new Vertex[size]; adj = new LinkedList[size]; for(int i=0; i*
  6. 深度優先遍歷
  7. / public static void dfs(Graph graph, int start, boolean[] visited) { System.out.println(graph.vertexes[start].data); visited[start] = true; for(int index : graph.adj[start]){ if(!visited[index]){ dfs(graph, index, visited); } } } /*
  8. 廣度優先遍歷
  9. */
  10. public static void bfs(Graph graph, int start, boolean[] visited, LinkedList queue) {
  11. queue.offer(start);
  12. while (!queue.isEmpty()){
  13. int front = queue.poll();
  14. if(visited[front]){
  15. continue;
  16. }
  17. System.out.println(graph.vertexes[front].data);
  18. visited[front] = true;
  19. for(int index : graph.adj[front]){
  20. queue.offer(index);;
  21. }
  22. }
  23. }
  24. public static void main(String[] args) {
  25. Graph graph = new Graph(6);
  26. graph.adj[0].add(1);
  27. graph.adj[0].add(2);
  28. graph.adj[0].add(3);
  29. graph.adj[1].add(0);
  30. graph.adj[1].add(3);
  31. graph.adj[1].add(4);
  32. graph.adj[2].add(0);
  33. graph.adj[3].add(0);
  34. graph.adj[3].add(1);
  35. graph.adj[3].add(4);
  36. graph.adj[3].add(5);
  37. graph.adj[4].add(1);
  38. graph.adj[4].add(3);
  39. graph.adj[4].add(5);
  40. graph.adj[5].add(3);
  41. graph.adj[5].add(4);
  42. System.out.println("圖的深度優先遍歷:");
  43. dfs(graph, 0, new boolean[graph.size]);
  44. System.out.println("圖的廣度優先遍歷:");
  45. bfs(graph, 0, new boolean[graph.size], new LinkedList());
  46. }

640?wx_fmt=jpeg

 

640?wx_fmt=jpeg

以上內容來自《漫畫算法》

640?wx_fmt=png

掃碼查看詳情

640?wx_fmt=png

小灰把兩年多以來積累的漫畫作品進行了篩選和優化,並加上了一些更爲基礎和系統的入門章節,最終完成了本書的六大篇章:

第一章 算法概述

介紹了算法和數據結構的相關概念,告訴大家算法是什麼,數據結構又是什麼,它們有哪些用途,如何分析時間複雜度,如何分析空間複雜度。

第二章 數據結構基礎

介紹了最基本的數據結構,包括數組、鏈表、棧、隊列、哈希表的概念和讀寫操作。

第三章 樹

介紹了樹和二叉樹的概念、二叉樹的各種遍歷方式、二叉堆和優先隊列的應用。

第四章 排序算法

介紹了幾種典型的排序算法,包括冒泡排序、快速排序、堆排序、計數排序、桶排序。

第五章 面試中的算法

介紹了10餘道職場上流行的算法面試題及詳細的解題思路。例如怎樣判斷鏈表有環、怎樣計算大整數相加等。

第六章 算法的實際應用

介紹了算法在職場上的一些應用,例如使用LRU算法來淘汰冷數據,使用Bitmap算法來統計用戶特徵等。

本書是全綵印製,書中的每一章、每一節、每一句話、每一幅圖、每一行代碼,都經過了小灰和編輯們的精心打磨,力求用最爲直白的方式把知識講明白、講透徹。

640?wx_fmt=png

 

640?wx_fmt=png

早期的漫畫中存在一些敘述錯誤和表達不清晰的地方,小灰在本書中做了修正和補充;同時書中增加了許多全新的篇章,使得本書的內容更加系統和全面。

從零開始的 Python 爬蟲速成指南,實用!

https://edu.csdn.net/topic/python115?utm_source=cxrs_bw

對於渴望學習算法的小夥伴,無論你是正在學習計算機專業的學生,還是已經進入職場的新人,亦或是擁有多年工作經驗卻不擅長算法的老手,這本《漫畫算法》都能幫助你告別對算法的恐懼,認識算法、掌握算法。

掃碼或者點擊閱讀原文購買

640?wx_fmt=png

購買前可使用優惠券哦

優惠券領取二維碼如下

640?wx_fmt=png

640?wx_fmt=gif

 

碼書商店是CSDN專爲我們的用戶建立的一個商店,這裏提供大量的技術書籍,除了書籍我們也提供生活類的相關產品,如耳機、鍵盤等,或者你們如果有需求也可以聯繫碼書商店的客服或者在公衆號下留言你們需要的產品,我們儘量滿足大家需求哦。

作爲碼書商店的運營人員,誠邀你們進入我們的“CSDN碼書福利羣”,羣裏會不定時的給大家贈書書籍、優惠券等,若加入時顯示二維碼已過期,也可加微信號“xthmily”,會拉你入羣哦

640?wx_fmt=png

 

點擊“閱讀原文”

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章