本文是對 Swift Algorithm Club 翻譯的一篇文章。
Swift Algorithm Club是 raywenderlich.com網站出品的用Swift實現算法和數據結構的開源項目,目前在GitHub上有18000+⭐️,我初略統計了一下,大概有一百左右個的算法和數據結構,基本上常見的都包含了,是iOSer學習算法和數據結構不錯的資源。
🐙andyRon/swift-algorithm-club-cn是我對Swift Algorithm Club,邊學習邊翻譯的項目。因爲能力有限,如發現錯誤或翻譯不妥,請指正,歡迎pull request。也歡迎有興趣、有時間的小夥伴一塊兒參與翻譯和學習🤓。固然也歡迎加⭐️,🤩🤩🤩🤨🤪。
本文的翻譯原文和代碼能夠查看🐙swift-algorithm-club-cn/Breadth-First Search前端
廣度優先搜索(BFS,Breadth-First Search)node
這個話題已經有個輔導文章git
廣度優先搜索(BFS,Breadth-First Search)是用於遍歷、搜索樹或圖數據結構的算法。它從源節點開始,在移動到下一級鄰居以前首先探索直接鄰居節點。github
廣度優先搜索能夠用於有向圖和無向圖。算法
如下是廣度優先搜索在圖上的工做原理:swift
當咱們訪問節點時,將其着色爲黑色。 還將其鄰居節點放入隊列。 在動畫中,入隊但還沒有訪問的節點以灰色顯示。數據結構
讓咱們按照動畫示例進行操做。 咱們從源節點A
開始,並將其添加到隊列中。 在動畫中,這顯示爲節點A
變爲灰色。app
queue.enqueue(A)
複製代碼
隊列如今是[A]
。 咱們的想法是,只要隊列中有節點,咱們就會訪問位於隊列前端的節點,若是還沒有訪問它們,則將其相鄰的鄰居節點入隊。學習
要開始遍歷圖,咱們將第一個節點從隊列中推出A
,並將其着色爲黑色。 而後咱們將它的兩個鄰居節點B
和C
入隊。 它們的顏色變成灰色。測試
queue.dequeue() // A
queue.enqueue(B)
queue.enqueue(C)
複製代碼
隊列如今是[B, C]
。 咱們將B
出列,並將B
的鄰居節點D
和E
排入隊列。
queue.dequeue() // B
queue.enqueue(D)
queue.enqueue(E)
複製代碼
隊列如今是[C, D, E]
。 將C
出列,並將C
的鄰居節點F
和G
入隊。
queue.dequeue() // C
queue.enqueue(F)
queue.enqueue(G)
複製代碼
隊列如今是[D, E, F, G]
。 出列D
,它沒有鄰居節點。
queue.dequeue() // D
複製代碼
隊列如今是[E, F, G]
。 將E
出列並將其單個鄰居節點H
排隊。 注意B
也是E
的鄰居,但咱們已經訪問了B
,因此咱們再也不將它添加到隊列中。
queue.dequeue() // E
queue.enqueue(H)
複製代碼
隊列如今是[F, G, H]
。 出隊F
,它沒有未訪問的鄰居節點。
queue.dequeue() // F
複製代碼
隊列如今是[G, H]
。 出列G
,它沒有未訪問的鄰居節點。
queue.dequeue() // G
複製代碼
隊列如今是[H]
。 出列H
,它沒有未訪問的鄰居節點。
queue.dequeue() // H
複製代碼
隊列如今爲空,這意味着已經探索了全部節點。 探索節點的順序是A
,B
,C
,D
,E
,F
,G
,H
。
咱們能夠將其顯示爲樹:
節點的父節點是"發現"該節點的節點。 樹的根是廣度優先搜索開始的節點。
對於未加權的圖,此樹定義從起始節點到樹中每一個其餘節點的最短路徑。 廣度優先搜索是在圖中找到兩個節點之間的最短路徑的一種方法。
使用隊列簡單實現廣度優先搜索:
func breadthFirstSearch(_ graph: Graph, source: Node) -> [String] {
var queue = Queue<Node>()
queue.enqueue(source)
var nodesExplored = [source.label]
source.visited = true
while let node = queue.dequeue() {
for edge in node.neighbors {
let neighborNode = edge.neighbor
if !neighborNode.visited {
queue.enqueue(neighborNode)
neighborNode.visited = true
nodesExplored.append(neighborNode.label)
}
}
}
return nodesExplored
}
複製代碼
雖然隊列中有節點,但咱們訪問第一個節點,而後將其還沒有被訪問的直接鄰居節點入隊。
將此代碼放在 playground中, 並進行以下測試:
let graph = Graph()
let nodeA = graph.addNode("a")
let nodeB = graph.addNode("b")
let nodeC = graph.addNode("c")
let nodeD = graph.addNode("d")
let nodeE = graph.addNode("e")
let nodeF = graph.addNode("f")
let nodeG = graph.addNode("g")
let nodeH = graph.addNode("h")
graph.addEdge(nodeA, neighbor: nodeB)
graph.addEdge(nodeA, neighbor: nodeC)
graph.addEdge(nodeB, neighbor: nodeD)
graph.addEdge(nodeB, neighbor: nodeE)
graph.addEdge(nodeC, neighbor: nodeF)
graph.addEdge(nodeC, neighbor: nodeG)
graph.addEdge(nodeE, neighbor: nodeH)
graph.addEdge(nodeE, neighbor: nodeF)
graph.addEdge(nodeF, neighbor: nodeG)
let nodesExplored = breadthFirstSearch(graph, source: nodeA)
print(nodesExplored)
複製代碼
結果輸出: ["a", "b", "c", "d", "e", "f", "g", "h"]
廣度優先搜索可用於解決許多問題。 例如:
做者:Chris Pilcher, Matthijs Hollemans
翻譯:Andy Ron
校對:Andy Ron