最短路径的最简单的递归思想就是:
- 从起始点start到某一个顶点v的最短路径,等于该顶点v的所有邻接点到start的最短路径加上这些邻接点到该点的路径中的最小数据
- 用伪代码表示即:
shortest[ start -> v ] = min{ shortest[ start -> neighbor(v) ] + weight(v -> neighbor(v)) }
- 如此递归,直到找到起始点start
使用迭代思想实现:
- 就是直接从起始点start开始找start邻接点的最小路径长度
- 由上一条可以知道,start到其邻接点的最小长度中的最小值,一定是该顶点的最终最小路径长度(这一点很重要)。即假设start的邻接点有i, j,k等等,start到i的距离(即权重)最小,那么start不可能有更小的路径,间接地从j,k等邻接点到达i。
- 套用上一条结论,找到当前所有已知距离中的最小值,其对应的顶点即是已找到最短路径
- 继续对该顶点的其余邻接点进行遍历,并对从start到邻接点的最小距离进行更新,然后对更新后的距离进行上一步操作,原理基本一致
- 遍历完成之后可以知道从start到任意一点的最短路径
java实现:
public class Dijikstra {
static final int N = Integer.MAX_VALUE / 2; // 定义一个无穷数,表示不直接连通
public static void main(String[] args) {
int[][] vex = new int[][] { // 邻接图矩阵
{0, 3, 9, 6, N},
{3, 0, 5, N, 6},
{9, 5, 0, 4, 2},
{6, N, 4, 0, 1},
{N, 6, 2, 1, 0}
};
MyGraph G = new MyGraph(vex); // 生成MyGraph图简易结构
int path[] = new int[G.numVertex]; // 记录到达顶点i的前一个顶点path[i], 即前驱顶点
int weight[] = new int[G.numVertex]; // 记录到达i顶点的最小总权值(距离)weight[i]
shortestPath(G, 0, path, weight); // 输入起始点, 开始遍历
// 执行完毕, 打印结果
System.out.print("\n");
for(int x: path) {
System.out.print(x + " ");
}
System.out.print("\n");
for(int x: weight) {
System.out.print(x + " ");
}
}
/**
* MyGraph G: 要遍历的图
* int start: 起始目标点
* int weight[], path[]: 保存权值和路径信息
*/
public static void shortestPath(MyGraph G, int start, int weight[], int path[]) {
int w = start;
boolean isFinal[] = new boolean[G.numVertex]; // isFinal[i]标记是否起始点start已找到顶点i的最终最短路径
// isFinal标记防止重复遍历
for(int i = 0; i < G.numVertex; i++) {
// 初始化起始点数据
weight[i] = G.vertex[start][i];
path[i] = 0;
}
isFinal[start] = true; // 起始点不用遍历, 标记为true, 其它默认false
for(int v = 1; v < G.numVertex; v++) { // 最多遍历n - 1个顶点, 即n - 1次
int min = N; // 中间变量记录最小值
for(int k = 0; k < G.numVertex; k++) {
// 遍历weight数组, 找到从start开始到所有其它顶点的临时最小路径中的最小值
if(!isFinal[k] && weight[k] < min) {
min = weight[k]; // 记录最小值
w = k; // 记录该最小值的顶点序号
}
}
isFinal[w] = true; // 因为上面每次都找最小的路径, 所以可以确定w顶点的临时最小路径就是最终的, 标记为true
for(int k = 0; k < G.numVertex; k++) {
// 将w顶点的邻接点加入weight数组, 取最小路径(这个最小是临时的, 后面可能会被更小的覆盖)
if(!isFinal[k] && (min + G.vertex[w][k] < weight[k])) {
weight[k] = min + G.vertex[w][k]; // 记录k顶点临时最小路径
path[k] = w; // 记录k顶点的前驱顶点为w
}
}
}
}
}
// 简单定义一个图存储结构
class MyGraph {
int[][] vertex;
int numVertex;
public MyGraph(int[][] vex){
this.vertex = vex.clone();
this.numVertex = vertex.length; // 行数即顶点数
}
}