4.2.1 单点最短路径
- 问题:给定一幅图和一个起点s,问从s到给定顶点v是否存在一条路径?如果有,找出其中最短的一条
- 思路:要找到s到v的最短路径,从s开始,在所有的距离为1的点中找v,如果没有,则到距离为2的点中找v,如此反复
广度优先搜索(BFS)和深度优先搜索(DFS)
- DFS:选用递归(隐式栈),使用LIFO规则从有带搜索的通道中选择最晚遇到的那条往下走
- BFS:按照与起点的距离顺序来遍历所有顶点,使用(FIFO)队列实现,从有带搜索的通道中选择最早遇到的那条
实现
public class BreadthFirstPaths { private boolean[] marked;//是否之前已有更短路径到达 private int[] edgeTo;//到达该结点已知路径上的最后顶点 private final int s; public BreadthFirstPaths(Graph G, int s){ marked = new boolean[G.V()]; edgeTo = new int[G.V()]; this.s = s; bfs(G,s); } (队列) public void bfs(Graph G, int s){ Queue<Integer> queue = new Queue<>(); marked[s] = true; queue.enqueue(s); while (! queue.isEmpty()){ int v = queue.dequeue(); for (int w: G.adj(v)){ if (!marked[w]){ edgeTo[w] = v;//保存已知路径最后一个顶点 marked[w] = true;//标记为已达点 queue.enqueue(w);//添加至队列 } } } } private boolean hasPathTo(int v){ return marked[v]; } //返回s到v的最短路径 public Iterable<Integer> pathTo(int v){ if (!hasPathTo(v)) return null; Stack<Integer> path = new Stack<>(); for (int i = v; i != s; i = edgeTo[i]) path.push(i); path.push(v); return path; }}
- 虽然和DFS的pathTo()实现方法一样但BFS会给出s到v的一段最短路径
算法分析
- 对于从s可达的任意顶点v,BFS都可以找到一条从s到v的最短路径
- BFS搜索时间在最坏情况下和V+E成正比
BFS和DFS对比
- 相同点:
- 搜索时都会先将起点存入数据结构中,然后重复一下操作指导数据结构被清空
- 取下一个顶点并标记
- 将v的所有相邻而又未被标记的顶点继续加入数据结构
- 不同点:
- DFS选取递归/隐式栈,每次将最晚一个加入的结点当作下一个顶点
- BFS选取队列,每次将最早一个加入的结点当作下一个顶点