BFS是用来遍历一张图的最简单演算法,也是很多在图论演算法的原型,许多演算法都是基於BFS,像是Prim最小生成树,Dijkstra演算法等等。
给定一张图,和一个节点s,BFS可以走访s能够到达的所有节点v,并且能够纪录s到各个节点的最少边数,也就是最短距离,同时会产生出一棵BST Tree。这个数会以s作为树的根结点,并且包含s能够到达的所有节点v。BST可以用在有向图,也可以用在无向图中。
为了方面演示这个演算法,我们将结点以三个颜色做为表示,白色,灰色,黑色做为表示。所有节点在一开始的时候都标记为白色,在BST持续进行的过程,这些节点会变成灰色或是黑色。在遍历的过程中,第一次遇到的节点就称为该节点被发现,并且同时节点的颜色发生改变,黑色和灰色皆为已经被发现的节点。
白色表示还没被其他节点发现的节点,灰色表示被其他节点发现的节点,且被推入Queue中,黑色表示被其他节点发现得节点,且已经被Pop出Queue。
下面为BFS的虚拟码,假设给定图,以邻接矩阵表示,每一个节点作为物件表示,节点的颜色储存在中,储存前驱节点,如果不存在节点,则表示为NULL,纪录s到u的距离。这个演算法还需要一个Queue来储存灰色的节点。
BFS(G, s)
for each vertex u ∈ G.V - {s}
u.color = WHITE
u.d = ∞
u.π = NULL
s.color = GRAY
s.d = 0
s.π = NULL
Q = ∅
ENQUEUE(Q, s)
while Q != ∅
u = DEQUEUE(Q)
for each v ∈ G.Adj[u]
if v.color == WHITE
v.color = GRAY
v.d = u.d + 1
v.π = u
ENQUEUE(Q, v)
u.color = BLACK
在BFS中,一开始构建出的BFS Tree只会有一个根结点s,在遍历过程中看到u节点的邻接串列时,每当发现到一个白色节点v,就将结点v和边加入到树中。BFS Tree中,称u节点是v节点的前驱点或是父节点。
在虚拟码1到4行中,我们先将s节点从G.V集合中移出,并遍历除了s的所有节点,都将他标记成白色,并将每一个节点的u.d标记成无限,无限的概念就是走不到的意思,引申为还没走到的节点,并将每一个父节点标记成NULL。
在第5行将s标记成灰色,因为在BST最一开始时,我们便发现到s了,并且只有s是没有被标记成白色的,第6行和第7行初始化s。第8,9行初始化Queue,Queue的初始状态下,里面只有s。
第10行到18行while回圈一直执行到没有灰色节点为止,在第一次迭代,只有s节点是灰色的,Queue中也是只有s节点,直到第11行Pop出来。
第12行到17行for回圈对u节点的邻接串列中每一个节点v进行探测,如果v为白色,表示还没被发现,使用第14行到17行来发现节点,将刚刚白色的v节点涂上灰色,并将v.d = u.d + 1,改变距离,并将u当作是v的父节点,然後插入到Queue的尾端。
在第18行,检查u的邻接串列中所有节点後,将u节点标记成黑色。
以树的形式来看BFS,就可以发现到广度优先的特性了,我们可以观察到我们是一层接着一层的去遍历整棵树,而这个特性可以给予我们到某一个节点的最短路径,BFS好处在於可以告诉我们哪一些节点是s抵达不了的。
从上面的例子观察到,每一个节点最多就是出队和入队各一次,而Queue的入队和出队操作皆为,总共在集合G.V中有|V|个节点,因此时间复杂度为。BFS只有在节点出队的时候才会对节点对应到的邻接串列进行遍历,而无论是有向图,还是无向图,他们的邻接串列的长度皆为,而整体BFS所需要的时间复杂度为,而这是一个线性函数。
BFS可以找到从s节点到u节点之最短距离,我们定义从源节点s到v之间的最短距离$\delta(s,v)$之间所有路径中具有最少边数的路径,如果u节点是s不可抵达的,则距离为无限,也就是$\delta(s,v) = \infty$
参考资料:Introductio to algorithms 3rd, Wiki, 101北一女资讯集训
案例说明及适用场景 所有的公司都需要人事、薪资及差勤,但大部份的系统都独立在外 一方面是人资系统确实...
What is MVC? 先招唤 wiki 大大出来解释一下 MVC 是甚麽: MVC模式(Mode...
前言 Python虽然可以直接使用Windows的Console直接执行程序,但是不只对於笔者,对於...
友:你要不要一起参加铁人赛? 我:好啊! (几天後) 我:乾我不小心忘了报名...... ----...
Binary Search Tree III 树主要有三种走访的方式,分别是InOrder、PreO...