回答
你應該先看看http://en.wikipedia.org/wiki/Breadth-first_search。
下面是一個快速實現,其中我使用列表列表來表示路徑隊列。
# graph is in adjacent list representation
graph = {
'1': ['2', '3', '4'],
'2': ['5', '6'],
'5': ['9', '10'],
'4': ['7', '8'],
'7': ['11', '12']
}
def bfs(graph, start, end):
# maintain a queue of paths
queue = []
# push the first path into the queue
queue.append([start])
while queue:
# get the first path from the queue
path = queue.pop(0)
# get the last node from the path
node = path[-1]
# path found
if node == end:
return path
# enumerate all adjacent nodes, construct a new path and push it into the queue
for adjacent in graph.get(node, []):
new_path = list(path)
new_path.append(adjacent)
queue.append(new_path)
print bfs(graph, '1', '11')
另一種方法是保持從每個節點映射到它的父,並且檢查所述鄰接節點的情況下,記錄它的父。搜索完成後,根據父映射進行回溯。
graph = {
'1': ['2', '3', '4'],
'2': ['5', '6'],
'5': ['9', '10'],
'4': ['7', '8'],
'7': ['11', '12']
}
def backtrace(parent, start, end):
path = [end]
while path[-1] != start:
path.append(parent[path[-1]])
path.reverse()
return path
def bfs(graph, start, end):
parent = {}
queue = []
queue.append(start)
while queue:
node = queue.pop(0)
if node == end:
return backtrace(parent, start, end)
for adjacent in graph.get(node, []):
if node not in queue :
parent[adjacent] = node # <<<<< record its parent
queue.append(adjacent)
print bfs(graph, '1', '11')
上述代碼基於沒有周期的假設。
這很棒!我的思維過程使我相信創建某種類型的表格或矩陣,我還沒有學習圖表。謝謝。 –
我也嘗試使用回溯方法,雖然這看起來更清潔。如果你只知道開始和結束,但是沒有中間的節點,是否可以繪製圖形?甚至還有另一種方法除了圖表? –
@ChristopherM我沒有理解你的問題:( – qiao
我想我會嘗試代碼這件事的樂趣:
graph = {
'1': ['2', '3', '4'],
'2': ['5', '6'],
'5': ['9', '10'],
'4': ['7', '8'],
'7': ['11', '12']
}
def bfs(graph, forefront, end):
# assumes no cycles
next_forefront = [(node, path + ',' + node) for i, path in forefront if i in graph for node in graph[i]]
for node,path in next_forefront:
if node==end:
return path
else:
return bfs(graph,next_forefront,end)
print bfs(graph,[('1','1')],'11')
# >>>
# 1, 4, 7, 11
如果你想要週期,你可以補充一點:
for i, j in for_front: # allow cycles, add this code
if i in graph:
del graph[i]
+1,你讓我想起了一件事:'假設沒有周期':) – qiao
你會在哪裏添加這段代碼? – Liondancer
構建next_for_front後。關於問題的後續問題,如果圖形包含循環會怎麼樣?例如。如果節點1有一條連接回自己的邊緣?如果圖形在兩個節點之間有多條邊,會怎麼樣? –
我喜歡喬的第一個答案非常感謝! 這裏缺少的唯一東西是將頂點標記爲已訪問。
爲什麼我們需要這樣做?
讓我們想象一下,有從節點11連接的另一個節點13號現在我們的目標是要找到節點13
運行的一點點後,隊列將是這樣的:
[[1, 2, 6], [1, 3, 10], [1, 4, 7], [1, 4, 8], [1, 2, 5, 9], [1, 2, 5, 10]]
注在結尾處有兩個節點號爲10的路徑。
這意味着來自節點號碼10的路徑將被檢查兩次。在這種情況下,它看起來不那麼糟糕,因爲節點號10沒有任何子節點。但它可能非常糟糕(即使在這裏,我們將無故查看該節點兩次。)
節點號13 isn' t,因此程序在到達第二條路徑之前將不會返回,並且結尾號爲10 ..我們將重新檢查它..
我們所缺少的是一組標記訪問節點,而不是再次檢查他們..
這是修改後的喬代碼:
graph = {
1: [2, 3, 4],
2: [5, 6],
3: [10],
4: [7, 8],
5: [9, 10],
7: [11, 12],
11: [13]
}
def bfs(graph_to_search, start, end):
queue = [[start]]
visited = set()
while queue:
# Gets the first path in the queue
path = queue.pop(0)
# Gets the last node in the path
vertex = path[-1]
# Checks if we got to the end
if vertex == end:
return path
# We check if the current node is already in the visited nodes set in order not to recheck it
elif vertex not in visited:
# enumerate all adjacent nodes, construct a new path and push it into the queue
for current_neighbour in graph_to_search.get(vertex, []):
new_path = list(path)
new_path.append(current_neighbour)
queue.append(new_path)
# Mark the vertex as visited
visited.add(vertex)
print bfs(graph, 1, 13)
該方案的輸出將是:
[1, 4, 7, 11, 13]
沒有unneccecery rechecks ..
對'queue'使用'collections.deque'作爲list.pop(0)產生'O(n)'內存移動可能是有用的。另外,爲了後代,如果你想做DFS,只需設置'path = queue.pop()',在這種情況下,變量'queue'實際上就像一個'stack'。 – Sudhi
我喜歡@Qiao第一回答和@ Or的加法。爲了減少處理,我想添加Or的答案。
In @ Or的回答跟蹤訪問節點很棒。我們也可以讓程序儘早退出。在for循環中的某個點,current_neighbour
必須是end
,一旦發生這種情況,找到最短路徑並返回程序。
我想修改的方法如下,狠抓for循環
graph = {
1: [2, 3, 4],
2: [5, 6],
3: [10],
4: [7, 8],
5: [9, 10],
7: [11, 12],
11: [13]
}
def bfs(graph_to_search, start, end):
queue = [[start]]
visited = set()
while queue:
# Gets the first path in the queue
path = queue.pop(0)
# Gets the last node in the path
vertex = path[-1]
# Checks if we got to the end
if vertex == end:
return path
# We check if the current node is already in the visited nodes set in order not to recheck it
elif vertex not in visited:
# enumerate all adjacent nodes, construct a new path and push it into the queue
for current_neighbour in graph_to_search.get(vertex, []):
new_path = list(path)
new_path.append(current_neighbour)
queue.append(new_path)
#No need to visit other neighbour. Return at once
if current_neighbour == end
return new_path;
# Mark the vertex as visited
visited.add(vertex)
print bfs(graph, 1, 13)
輸出和一切將是相同的。但是,代碼將花費更少的時間來處理。這在更大的圖表上特別有用。我希望這可以幫助未來的人。
- 1. 最短路徑 - 廣度優先搜索
- 2. 廣度優先搜索 - 不返回路徑(正確路徑)
- 3. 廣度優先搜索 - Java
- 4. 廣度優先搜索
- 5. 廣度優先搜索java.lang.NullPointerException
- 6. Java廣度優先搜索?
- 7. 廣度優先搜索和深度優先搜索
- 8. 深度優先搜索和廣度優先搜索瞭解
- 9. 如何實現廣度優先搜索?
- 10. 如何使用廣度優先搜索在迷宮中找到最短路徑?
- 11. 如何在廣度優先搜索中快速找到最短路徑?
- 12. 帶路徑跟蹤的廣度優先搜索,一些座標被「跳過」
- 13. 優先深度優先搜索廣度優先搜索或反之亦然
- 14. 實現A * - 搜索作爲廣度優先搜索/深度優先搜索
- 15. F#中的廣度優先搜索(BFS)
- 16. 廣度優先搜索查詢在MYSQL
- 17. 深度或廣度優先搜索?
- 18. 跟蹤深度非遞歸廣度優先搜索
- 19. 在prolog中使用廣度優先搜索返回最短路徑
- 20. 廣度優先或深度優先搜索
- 21. 廣度優先與深度優先搜索的輸入/輸出
- 22. 將廣度優先搜索轉換爲深度優先使用Java搜索
- 23. 廣度優先搜索/深度優先搜索還是定向圖?
- 24. 功能廣度優先搜索
- 25. BFS代碼(廣度優先搜索)
- 26. 並行廣度優先搜索
- 27. 廣度優先搜索 - 標準Python庫
- 28. 廣度優先搜索解決難題
- 29. 廣度優先搜索使用陣列
- 30. 廣度優先搜索練習 - AI
根據凱文培根法,這實際上是幾個月前我幫助朋友的一項舊任務。我的最終解決方案非常草率,我基本上做了另一個廣度優先搜索來「倒帶」和回溯。我不想找到更好的解決方案。 –
優秀。我認爲重新審視一個老問題,試圖找到一個更好的答案,成爲工程師的一個令人欽佩的特徵。祝你在學習和事業上順利。 –
感謝您的好評,我只相信如果我現在不學,我會再次面對同樣的問題。 –