BFS算法整理(python實現)
廣度優先算法(Breadth-First-Search),簡稱BFS,是一種圖形搜索演算算法。
1. 算法的應用場景
2. 算法的模板
2.1 針對樹的BFS模板
- 無需分層遍歷
from collections import deque
# Definition for a binary tree node.
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
def level_order_tree(root, result):
if not root:
return
# 這里借助python的雙向隊列實現隊列
# 避免使用list.pop(0)出站的時間復雜度為O(n)
queue = deque([root])
while queue:
node = queue.popleft()
# do somethings
result.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return result
if __name__ == "__main__":
tree = TreeNode(4)
tree.left = TreeNode(9)
tree.right = TreeNode(0)
tree.left.left = TreeNode(5)
tree.left.right = TreeNode(1)
print(level_order_tree(tree, []))
# [4, 9, 0, 5, 1]
- 需要分層遍歷
def level_order_tree(root):
if not root:
return
q = [root]
while q:
new_q = []
for node in q:
# do somethins with this layer nodes...
# 判斷左右子樹
if node.left:
new_q.append(node.left)
if node.right:
new_q.append(node.right)
# 記得將舊的隊列替換成新的隊列
q = new_q
# 最后return想要返回的東西
return xxx
2.2 針對圖的BFS
- 無需分層遍歷的圖
from collections import deque
def bsf_graph(root):
if not root:
return
# queue和seen為一對好基友,同時出現
queue = deque([root])
# seen避免圖遍歷過程中重復訪問的情況,導致無法跳出循環
seen = set([root])
while queue:
head = queue.popleft()
# do somethings with the head node
# 將head的鄰居都添加進來
for neighbor in head.neighbors:
if neighbor not in seen:
queue.append(neighbor)
seen.add(neighbor)
return xxx
- 需要分層遍歷的圖
def bsf_graph(root):
if not root:
return
queue = [root]
seen = set([root])
while queue:
new_queue = []
for node in queue:
# do somethins with the node
for neighbor in node.neighbors:
if neighbor not in seen:
new_queue.append(neighbor)
seen.add(neighbor)
return xxx
2.3 拓撲排序
在圖論中,由一個有向無環圖的頂點組成的序列,當且僅當滿足下列條件時,稱為該圖的一個拓撲排序(英語:Topological sorting)。
每個頂點出現且只出現一次;
若A在序列中排在B的前面,則在圖中不存在從B到A的路徑。
實際應用
- 檢測編譯時的循環依賴
- 制定有依賴關系的任務的執行順序(例如課程表問題)
算法流程
- 統計所有點的入度,並初始化拓撲排序序列為空。
- 將所有入度為0的點,放到如BFS初始的搜索隊列中。
- 將隊列中的點一個一個釋放出來,把訪問其相鄰的點,並把這些點的入度-1.
- 如何發現某個點的入度為0時,則把這個點加入到隊列中。
- 當隊列為空時,循環結束。
算法實現
class Solution():
def top_sort(self, graph):
node_to_indegree = self.get_indegree(graph)
# 初始化拓撲排序序列為空
order = []
start_nodes = [node for node in graph if node_to_indegree[node] == 0]
queue = collection.deque(start_nodes)
while queue:
head = queue.popleft()
order.append(node)
for neighbor in head.neighbors:
node_to_indegree[neighbor] -= 1
if node_to_indegree[neighbor] == 0:
queue.append(neighbor)
return order
def get_indegree(self, graph):
node_to_indegree = {x: 0 for x in graph}
for node in graph:
for neighbor in node.neighbors:
node_to_indegree[neighbor] += 1
return node_to_indegree