算法-03 | 深度優先DFS| 廣度優先BFS | 剪枝優化


 

1. 搜索算法

在樹(圖/狀態集)中尋找特定節點

深度優先搜索算法和廣度優先搜索算法都是基於“圖”這種數據結構。

圖上的搜索算法就是,在圖中找出從一個頂點出發,到另一個頂點的路徑。圖上的搜索算法有深度優先、廣度優先搜索算法,和A*A∗、IDA*IDA∗ 等啟發式搜索算法。

廣度優先搜索和深度優先搜索是圖上的兩種最常用、最基本的搜索算法,僅適用於狀態空間不大的搜索。它們比A*A∗、IDA*IDA∗ 等啟發式搜索算法要簡單粗暴,沒有什么優化,所以也叫作暴力搜索算法。

廣度優先搜索,采用地毯式層層推進,從起始頂點開始,依次往外遍歷。廣度優先搜索需要借助隊列來實現,遍歷得到的路徑就是起始頂點到終止頂點的最短路徑。

深度優先搜索,采用回溯思想,適合用遞歸或棧來實現。遍歷得到的路徑並不是最短路徑。

深度優先和廣度優先搜索的時間復雜度都是 O(E),空間復雜度都是 O(V)。其中E代表邊,O代表頂點。

搜索 -- 遍歷

  • 每個節點都要訪問一次
  • 每個節點僅僅要訪問一次
  • 對於節點的訪問順序不限

    - 深度優先:depth first search
    - 廣度優先:breadth first search

     還有是按照優先級優先進行搜索,(可按現實場景進行定義,更適合於現實中很多的業務場景。這種算法稱為 啟發式搜索

2. 深度優先搜索

“走迷宮”。假設你站在迷宮的某個岔路口,然后想找到出口。你隨意選擇一個岔路口來走,走着走着發現走不通的時候,你就回退到上一個岔路口,重新選擇一條路繼續走,直到最終找到出口。這種走法就是一種深度優先搜索策略。實線箭頭表示遍歷,虛線箭頭表示回退。但深度優先搜索最先找出來的路徑,並不是頂點 s 到頂點 t 的最短路徑。深度優先搜索用的是回溯思想,回溯思想非常適合用遞歸來實現。

                                        

 

 

   黑色表起始點,紅色表終點。按照左下右上的方向順序走,即,如果左邊可以走,我們先走左邊。然后遞歸下去,沒達到終點或者走不通了,回溯上一個位置......

  首先往左走,走不通了就回溯到上一步(左右都走過了再回溯)、上一步到起點,按左下右上的順序走。

                                   

 

深度優先搜索 Depth-First-Search

遍歷順序 : 用棧

 

 

  

  

 DFS python代碼模板

DFS 代碼 - 遞歸寫法
visited = set()
def dfs(node, visited):
    if node in visited: # terminator
        # already visited
        return
    visited.add(node)
    # process current node here.
    ...
    for next_node in node.children():
        if not next_node in visited:
            dfs(next_node, visited)
 

DFS 代碼 - 非遞歸寫法
def DFS(self, tree):
    if tree.root is None:
        return []
    visited, stack = [], [tree.root]
    while stack:
        node = stack.pop()
        visited.add(node)
        process (node)
        nodes = generate_related_nodes(node)
        stack.push(nodes)
    # other processing work
    ...
View Code

 

 

3. 廣度優先搜索 Breadth-First-Search - BFS

廣度優先搜索(Breadth-First-Search),簡稱 BFS。它是一種“地毯式”層層推進的搜索策略,即先查找離起始頂點最近的,然后是次近的,依次往外搜索:

廣度優先搜索較之深度優先搜索之不同在於,深度優先搜索旨在不管有多少條岔路,先一條路走到底,不成功就返回上一個路口然后就選擇下一條岔路,而廣度優先搜索旨在面臨一個路口時,把所有的岔路口都記下來,然后選擇其中一個進入,然后將它的分路情況記錄下來,然后再返回來進入另外一個岔路,並重復這樣的操作。

       

順序遍歷: 用隊列

 

 

  

  BFS的python代碼模板:

BFS 代碼
def BFS(graph, start, end):
    queue = []
    queue.append([start])
    visited.add(start)
    while queue:
        node = queue.pop()
        visited.add(node)
        process(node)
        nodes = generate_related_nodes(node)
        queue.push(nodes)
    # other processing work
    ...
 

DFS 代碼 - 遞歸寫法
visited = set()
def dfs(node, visited):
    visited.add(node)
    # process current node here.
    ...
    for next_node in node.children():
        if not next_node in visited:
            dfs(next node, visited)
View Code

 

 

https://www.geeksforgeeks.org/difference-between-bfs-and-dfs/

4. DFS| BFS 與 Tree的遍歷的關系

A Tree is typically traversed in two ways:

                                                                    

 

 

BFS and DFSs of above Tree Breadth First Traversal : 1 2 3 4 5 Depth First Traversals: Preorder Traversal : 1 2 4 5 3 Inorder Traversal : 4 2 5 1 3 Postorder Traversal : 4 5 2 3 1

All four traversals require O(n) time as they visit every node exactly once.

here is difference in terms of extra space required.

  1. Extra Space required for Level Order Traversal is O(w) where w is maximum width of Binary Tree. In level order traversal, queue one by one stores nodes of different level.
  2. Extra Space required for Depth First Traversals is O(h) where h is maximum height of Binary Tree. In Depth First Traversals, stack (or function call stack) stores all ancestors of a node.

 

https://xiaqiu2233.github.io/2017/10/04/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E5%B9%BF%E5%BA%A6%E5%92%8C%E6%B7%B1%E5%BA%A6%E4%BC%98%E5%85%88%E9%81%8D%E5%8E%86%EF%BC%88%E5%85%88%E5%BA%8F%E3%80%81%E4%B8%AD%E5%BA%8F%E3%80%81%E5%90%8E%E5%BA%8F%EF%BC%89/

 

https://www.geeksforgeeks.org/bfs-vs-dfs-binary-tree/

 

5. 高級搜索

初級搜索(傻搜,暴力搜索): 1. 朴素搜索 2. 優化方式:不重復(fibonacci)、剪枝(生成括號問題) 如斐波拉契問題; 所謂剪枝就是整個狀態樹這個分支沒有必要的時候就把它剪掉,不進行搜索。 3. 搜索方向: DFS: depth first search 深度優先搜索 (傻子搜索, 一路不回頭直到撞了南牆) BFS: breadth first search 廣度優先搜索 (距離最近的) 雙向搜索(從起點和終點分別做一個廣度優先,然后在中間相遇,它的時間更快)、 啟發式搜索也叫A*算法或優先級搜索(不是用棧或隊列,而是用一個優先隊列放里邊,優先隊列是按照這個結的優先級,有些結點更可能會達到我們需要的結果,先就把它從隊列中拿出來進行搜索) 之所以分DFS和BFS是因為計算機數據結構里有一個先入后出的棧和 先入先出的隊列;

 雙向BFS

Breadth First Search(BFS)

   

  Breadth First Search Levels

     

Two-ended BFS 雙向BFS

  A和L各從兩邊擴散,直到兩者相遇,A、L各自所走的路徑和。

啟發式搜索

啟發式搜索 Heuristic Search(A*) 也叫智能搜索 或者 根據某項條件來不斷地優化搜索的方向。

一邊搜索一邊思考 <--> 也叫思考型搜索 ; 

通過優先級不斷地去找要找的點,先用優先級高的拿出來搜索;

啟發式搜索它也是基於BFS的。

 

A* 也是基於 BFS 代碼 def BFS(graph, start, end):   queue = []   queue.append([start])   visited.add(start) while queue:   node = queue.pop() #queue每次都pop一個最近的元素, can we add more intelligence here ? 在pop node時多加一些智能的元素在里面,不再使用queue的傻子似的先入先出。可以使用優先隊列。
  visited.add(node) 
  process(node)   nodes
= generate_related_nodes(node)   queue.push(nodes)
A* search的模板如下:
def AstarSearch(graph, start, end):   pq = collections.priority_queue() # 優先級 —> 估價函數   pq.append([start])   visited.add(start)   while pq:     node = pq.pop() # can we add more intelligence here ?     visited.add(node)
    process(node)     nodes
= generate_related_nodes(node)     unvisited = [node for node in nodes if node not in visited]     pq.push(unvisited)

使用了PQ即priority queue;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM