数据结构 JAVA描述(八) 最短路径+拓扑排序+关键路径

最短路径

迪杰斯特拉算法

原文分析思路(理解不了这里就pass掉):在有向网中,从某一源点到其余各点都有一条最短路径。首先在这些最短路径中,长度最短的必定只有一条弧,且它的权值是从源点出发的所有弧上权的最小值;其次,第二条长度次短的最短路径只可能有两种情况:

  • 从源点出发的一条弧,权值大于已求的最短路径的那条弧,但小于其他的从源点出发的弧的权值

  • 是一条经过已求得最短路径的路径

该算法需要引入辅助数组D,每个分量D[i]存放当前所找到的从源点到各个终点vi的最短路径的长度。过程是:

  • (1)令S = {v},其中v为源点,并设定D[i] 的初始值为:D[i] = |v,vi|

  • (2)选择顶点vj使得:D[j] = min{D[i]}(i∈V-S),并将vj并入到S中

  • (3)对集合V-S的所有顶点vk,若D[j] + |vj,vk| < D[k],则修改D[k]的值

  • (4)重复(2)、(3)的操作共n-1次,由此求得的所有最短路径是按路径长度递增的序列

ShortestPath_DIJ

package Graph;

/**
 * @description 求最短路径的问题 迪杰斯特拉  算法
 *              (1)令S = {v},其中v为源点,并设定D[i] 的初始值为:D[i] = |v,vi|
 *              (2)选择顶点vj使得:D[j] = min{D[i]}(i∈V-S),并将vj并入到S中
 *              (3)对集合V-S的所有顶点vk,若D[j] + |vj,vk| < D[k],则修改D[k]的值
 *              (4)重复(2)、(3)的操作共n-1次,由此求得的所有最短路径是按路径长度递增的序列  
 * @date  2015年12月31日
 */
public class ShortestPath_DIJ {
   
    // v0到其余顶点的最短路径,若p[v][w]为true,则w是从v0到v当前求得最短路径上的顶点
    private boolean[][] P;

    // v0到其余顶点的最小带权长度 (是变化的,一旦发现更小的,就重新赋值,到最后就是最短路径长度了)
    private int[] D;

    private final static int INFINITY = Integer.MAX_VALUE;



    public boolean[][] getP() {
        return P;
    }

    public int[] getD() {
        return D;
    }

    /**
     * @description 用迪杰斯特拉算法求有向网的v0到其余顶点的最短路径p[v]及其权值D[v] 
     * @date  2015年12月31日
     */
    public void DIJ(MGraph G, int v0){
        int vexNum = G.getVexNum(); // 顶点数
        this.P = new boolean[vexNum][vexNum];
        this.D = new int[vexNum];
        //finish[v]为true当且仅当v属于S,即已经求得从v0到v的最短路径
        boolean[] finish = new boolean[vexNum];

        //初始化所有数据
        for(int v = 0; v < vexNum; v++){
            finish[v] = false;
            D[v] = G.getArcs()[v0][v];
            for(int w = 0; w < vexNum; w++){
                P[v][w] = false;
            }
            if(D[v] < INFINITY){
                P[v][v0] = true;
                P[v][v] = true;
            }
        }

        D[v0] = 0; //从v0开始,并入S集
        finish[v0] = true;

        int v = -1 ; // 这里的赋值没有什么实际意义,只是为了保证编译正确
        //开始主循环,每次求得v0到某个v顶点的最短路径,并将v加入到S集.循环n-1次
        for(int i = 1; i < vexNum; i++){
            int min = INFINITY; //当前所知离v0最近的距离
            for(int w = 0; w < vexNum; w++){
                if( !finish[w]){
                    if(D[w] < min){
                        v = w;
                        min = D[w];
                    }
                }
            }
            finish[v] = true; //离v0最近的v并入S

            //更新当前最短路径和距离
            for(int w = 0; w < vexNum; w++){
                if( !finish[w] && G.getArcs()[v][w] < INFINITY && (min + G.getArcs()[v][w] < D[w])){
                    D[w] = min + G.getArcs()[v][w];
                    //下面两句这么理解,现在路径是v0-v-w,所以经过了v点,那么v0到v的最小路径自然要给w,同时再加上w点(P[W][W] = true)
                    System.arraycopy(P[v], 0, P[w], 0, P[v].length);
                    P[w][w] = true;
                }
            }

        }
    }

        // 测试
    public static void main(String[] args) throws Exception {
        Object[] vexs = { "v0", "v1", "v2", "v3", "v4", "v5" };
        int[][] arcs = { { INFINITY, INFINITY, 10, INFINITY, 30, 100 },
                { INFINITY, INFINITY, 5, INFINITY, INFINITY, INFINITY },
                { INFINITY, INFINITY, INFINITY, 50, 
  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值