【譯】Swift算法俱樂部-廣度優先搜索

本文是對 Swift Algorithm Club 翻譯的一篇文章。
Swift Algorithm Clubraywenderlich.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,並將其着色爲黑色。 而後咱們將它的兩個鄰居節點BC入隊。 它們的顏色變成灰色。測試

queue.dequeue()   // A
queue.enqueue(B)
queue.enqueue(C)
複製代碼

隊列如今是[B, C]。 咱們將B出列,並將B的鄰居節點DE排入隊列。

queue.dequeue()   // B
queue.enqueue(D)
queue.enqueue(E)
複製代碼

隊列如今是[C, D, E]。 將C出列,並將C的鄰居節點FG入隊。

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
複製代碼

隊列如今爲空,這意味着已經探索了全部節點。 探索節點的順序是ABCDEFGH

咱們能夠將其顯示爲樹:

The BFS tree

節點的父節點是"發現"該節點的節點。 樹的根是廣度優先搜索開始的節點。

對於未加權的圖,此樹定義從起始節點到樹中每一個其餘節點的最短路徑。 廣度優先搜索是在圖中找到兩個節點之間的最短路徑的一種方法。

代碼

使用隊列簡單實現廣度優先搜索:

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"]

BFS有什麼用?

廣度優先搜索可用於解決許多問題。 例如:

  • 計算源節點和其餘每一個節點之間的最短路徑(僅適用於未加權的圖形)。
  • 在未加權的圖表上計算最小生成樹

做者:Chris Pilcher, Matthijs Hollemans
翻譯:Andy Ron
校對:Andy Ron

相關文章
相關標籤/搜索