美文网首页
Breadth-First Search(广度优先搜索)

Breadth-First Search(广度优先搜索)

作者: Bel李玉 | 来源:发表于2020-08-08 19:53 被阅读0次

在之前的文章中,我们了解到如何使用图来表达对象之间的关系。需要铭记的是对象是用顶点(vertices)表示,对象之间的关系是使用边(edge)表示。

bread-first search(BFS)算法是遍历图的一种算法,BFS可以解决很多问题,例如:
1,生成最小生成树。
2,找到顶点之间的潜在路径
3,找到两个顶点之间的最短路径。

示例

BFS是从图的任意一个顶点开始,然后访问它们所有的邻居顶点,重复以上操作,直到遍历完所有顶点。

我们通过以下无向图来探索BFS算法:


BFS1.png

高亮的顶点表示已经访问过的顶点

我们将使用 队列(queue)来记录顶点的访问顺序,队列FIFO的特性保证了我们在遍历的时候,先遍历其邻居,然后在遍历更深的一层。

BFS2.png
1,一开始,选择A作为起点,并且将它加入到 queue中,
2,由于队列不是空的,让队列出队,此时该值为 A,并且访问A,接下来,将A的所有邻居[B,D,C]入队。

⚠️⚠️⚠️当使顶点入队时,必须是还没访问过的顶点,并且不在队列中

BFS3.png
1,当 queue 非空时,将B顶点出队,并且访问B顶点,接下来,将B的邻居 [E]入队。因为 A已经访问过了,不需要再次将A入队,现在 队列里面的元素是 [D, C, E]。
2,下一个需要出队的顶点是D。D没有任何没有访问过的邻居,没有新顶点入队。当前队列里面的元素是 [C, E]。 BFS4.png

1,接下来,将C出队,并且将它们的邻居 [F,G]入队,现在队列里面的元素为 [E, F, G]。
到目前为止,我们已经访问了A的所有邻居!BFS算法开始访问第二层元素了。


BFS5.png

重复上面的操作,将G出队,没有新顶点元素入队。
1,将E出队,并访问,将E未访问过的的邻居H入队。现在队列里面的元素为 [F, G, H]。
2,将 F 出队,因为 E 和 C 已经访问过,G已经在当前队列中,所以没有新的顶点元素入队。


BFS6.png

1,最后,将 H 出队,由于现在队列里面已经没有元素了,BFS遍历结束。
2,在对顶点进行遍历时,遍历的元素按顺序可以重建一个类似于树的一种结构。结果和 二叉树的层级遍历一致。

实现

我们给图增加一个扩展:

extension Graph where Element: Hashable {

  func breadthFirstSearch(from source: Vertex<Element>)
      -> [Vertex<Element>] {
    var queue = QueueStack<Vertex<Element>>()
    var enqueued: Set<Vertex<Element>> = []
    var visited: [Vertex<Element>] = []

    // more to come

    return visited
  }
}

source为我们遍历图的起点,在这里我们使用了三种数据结构:
1,queue 用来记录接下来要访问的顶点。
2,enqueued 用来记录已访问的顶点,避免同一个顶点访问多次。我们使用 Set
3,visited 是一个数组,用来有序的存储已访问的元素。

接下来,我们来完善该实现:

queue.enqueue(source) // 1
enqueued.insert(source)

while let vertex = queue.dequeue() { // 2
  visited.append(vertex) // 3
  let neighborEdges = edges(from: vertex) // 4
  neighborEdges.forEach { edge in
    if !enqueued.contains(edge.destination) { // 5
      queue.enqueue(edge.destination)
      enqueued.insert(edge.destination)
    }
  }
}

1,在一开始,将 source 顶点入队。
2,将队列里面的元素出队,直到队列元素为空。
3,每当将元素出队时,将它将它加到有序数组中。
4,将出队元素的所有边进行遍历。
5,将出队元素没有访问过的顶点入队。

以上就是 BFS的全部了,我们来测试一下

let vertices = graph.breadthFirstSearch(from: a)
vertices.forEach { vertex in
  print(vertex)
}

我们看下输出打印结果:

0: A
1: B
2: C
3: D
4: E
5: F
6: G
7: H

最后附上本文的相关代码DataAndAlgorim

参考链接《Data Structures & Algorithms in Swift》

相关文章

网友评论

      本文标题:Breadth-First Search(广度优先搜索)

      本文链接:https://www.haomeiwen.com/subject/hsffdktx.html