BFS 和 DFS是简单且重要的图遍历算法。
BFS
BFS 可以计算出源节点S到任意可达节点的距离(一条简单路径,且经过的边数最少),或者说,在所有边的权重为1的情况下,源节点和任意可达节点的最短距离。算法始终在发现节点和未发现节点之间扩展,也就是说沿广度方向扩展。笼统的说:总会先发现,距离源节点为k的节点,然后才会发现距离源节点为k+1的节点。
伪代码
首先约定每个节点p拥有属性d和f,d用于标记当前节点与源节点的距离,f用于标记当前节点是否被发现。使用p.d, p.f的形式访问相应的属性。
BFS(S)
将除去源节点S以外的所有节点的到源节点距离d设为INF(无穷大),标记属性f为未发现。
将源节点d设为0,f设为已发现。
新建一个空队列q。
将节点S放入队列q中。
在队列不为空的情况下,重复以下操作:
1.将队首元素u取出。
2.将u的所有相邻且未发现节点属性d设为u.d + 1,属性f设为 已发现,并放入队列q中。
3.返回操作1。
时间复杂度
对于图G(V,E),因为每条边被访问次数为O(1),每个节点入队和出队一次,时间复杂度为 O(1),总的复杂度 为O(V+E).
DFS
DFS在运行过程中,节点的首次发现时间u.sd和发现完成时间u.fd(发现完成:所有相邻接点均被发现)是比较有用的属性。DFS总是沿着最近发现的节点进行探索,假设发现了节点u,并且节点u可达且未被发现的相邻接点为:v1,v2,v3,,vk.且从u出发访问的次序也是这个次序。算法会先发现v1,然后将v1所有可达节点发现完毕后,算法会返回上一层到u,然后从v2开始,重复以上操作。
伪代码
DFS()
将所有节点的标记属性f为未发现。
全局属性时间 t = 0;
对每一个未发现的节点u,然后,执行DFS_VISIT(u):
DFS_VISIT(s)
将节点s的发现时间设为s.sd = ++t;
属性f设为:已发现
对节点s相邻且未发现的所有节点执行DFS_VISIT(v);
将节点s的发现完成时间s.fd = ++t;
时间复杂度
和BFS分析方法类似,可得:O(V+E);
应用
BFS,DFS是搜索常用的策略,根据需要进行属性的添加和删除,DFS还可以用于拓扑排序。
主要参考: 算法导论