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 ...
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)
https://www.geeksforgeeks.org/difference-between-bfs-and-dfs/
4. DFS| BFS 與 Tree的遍歷的關系
A Tree is typically traversed in two ways:
- Breadth First Traversal (Or Level Order Traversal)
- Depth First Traversals
- Inorder Traversal (Left-Root-Right)
- Preorder Traversal (Root-Left-Right)
- Postorder Traversal (Left-Right-Root)
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.
- 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.
- 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://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;