理论知识
边的放松
边的放松(Edge Relaxation)是图算法中的一个关键操作,主要用于解决最短路径问题。它的核心思想是在遍历图的过程中,通过比较和更新路径的长度,逐步找到从起点到每个顶点的最短路径。
边的放松过程
假设我们有一个从顶点 v 到顶点 w 的边 e
,其权重为 weight(v, w)
。边的放松操作如下:
- 检查当前路径:检查通过 v 到达 w 的路径是否比已经记录的从起点到 w 的路径更短。
- 更新路径:如果通过 v 到达 w 的路径更短,则更新 w 的最短路径长度,并将 w 的前驱顶点设置为 v。
数学表达式为:
IF
d i s t T o [ w ] > d i s t T o [ v ] + w e i g h t ( v , w ) distTo[w]>distTo[v]+weight(v,w) distTo[w]>distTo[v]+weight(v,w)
THEN
d i s t T o [ w ] = d i s t T o [ v ] + w e i g h t ( v , w ) distTo[w]=distTo[v]+weight(v,w) distTo[w]=distTo[v]+weight(v,w)
e d g e T o [ w ] = e edgeTo[w]=e edgeTo[w]=e
其中:
distTo[w]
表示从起点到 w 的当前已知最短路径长度。distTo[v] + weight(v, w)
表示通过 v 到达 w 的路径长度。edgeTo[w]
表示当前最短路径中 w 的前驱节点。
已知树结点所对应的 distTo[] 值均为最短路径的长度。对于优先队列中的任意顶点 w,distTo[w]是从 s 到 w 的最短路径的长度,该路径上的中间顶点在树中且路径结束于横切边edgeTo[w]。优先级最小的顶点的 distTo[] 值就是最短路径的权重,它不会小于已经被放松过的任意顶点的最短路径的权重,也不会大于还未被放松过的任意顶点的最短路径的权重。这个顶点就是下一个要被放松的顶点。所有从 s 可达的顶点都会按照最短路径的权重顺序被放松。
实验数据
8
15
4 5 0.35
5 4 0.35
4 7 0.37
5 7 0.28
7 5 0.28
5 1 0.32
0 4 0.38
0 2 0.26
7 3 0.39
1 3 0.29
2 7 0.34
6 2 0.40
3 6 0.52
6 0 0.58
6 4 0.93
算法轨迹
是算法处理样图 tinyEWD.txt 时的轨迹。在这个例子中,算法构造最短路径
树的过程如下所述。
将顶点 0 添加到树中,将顶点 2 和 4 加入优先队列。
从优先队列中删除顶点 2,将 0 → 2 添加到树中,将顶点 7 加入优先队列。
从优先队列中删除顶点 4,将 0 → 4 添加到树中,将顶点 5 加入优先队列,边
4 → 7 失效。
从优先队列中删除顶点 7,将 2 → 7 添加到树中,将顶点 3 加入优先队列,边
7 → 5 失效。
从优先队列中删除顶点 5,将 4 → 5 添加到树中,将顶点 1 加入优先队列,边
5 → 7 失效。
从优先队列中删除顶点 3,将 7 → 3 添加到树中,将顶点 6 加入优先队列。
从优先队列中删除顶点 1,将 5 → 1 添加到树中,边 1 → 3 失效。
从优先队列中删除顶点 6,将 3 → 6 添加到树中。
代码实现
import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.StdOut;
public class myDijkstraSP {
private myDirectedEdge[] edgeTo;
private double[] distTo;
private myIndexMinPQ<Double> pq;
public myDijkstraSP(myEdgeWeightedDigraph G, int s)
{
edgeTo = new myDirectedEdge[G.V()];
distTo = new double[G.V()];
pq = new myIndexMinPQ<Double>(