最短路径之Dijikstra(java简单实现)

最短路径的最简单的递归思想就是:

  • 从起始点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;	// 行数即顶点数
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值