算法基础|迪杰斯特拉算法初次实现|DijkstraAlgorithm

讲解改天有空了再写

完整代码如下:

public class Dijkstra {
    public static void main(String[] args) {
        char[] vertex = { 'A', 'B', 'C', 'D', 'E', 'F', 'G' };
        //邻接矩阵
        int[][] matrix = new int[vertex.length][vertex.length];
        final int N = 1000;// 表示不可以连接
        matrix[0]=new int[]{N,5,7,N,N,N,2};
        matrix[1]=new int[]{5,N,N,9,N,N,3};
        matrix[2]=new int[]{7,N,N,N,8,N,N};
        matrix[3]=new int[]{N,9,N,N,N,4,N};
        matrix[4]=new int[]{N,N,8,N,N,5,4};
        matrix[5]=new int[]{N,N,N,4,5,N,6};
        matrix[6]=new int[]{2,3,N,N,4,6,N};
        Graph_Di graph_di = new Graph_Di(7);
        graph_di.vertexes = vertex;
        graph_di.edges =matrix;
        graph_di.dijkstra(0);
        System.out.println();
    }

}

class Graph_Di {
    int N;//顶点数
    char[] vertexes;
    int[][] edges;
    int[] minDis;
    int[] check;
    int[] preVertex;

    public Graph_Di(int nums) {
        N = nums;
        vertexes = new char[nums];
        edges = new int[nums][nums];
        minDis = new int[vertexes.length];
        check = new int[vertexes.length];
        preVertex = new int[vertexes.length];

    }

    /**
     * 迪杰斯特拉算法入口方法
     * @param start
     */
    public void dijkstra(int start) {
        //构建用到的三张表,最小值表、前驱表
        // 手动生成preVertex表
        Arrays.fill(preVertex, start);
        // 手动横撑距离表
        Arrays.fill(minDis, 1000);
        minDis[start] = 0;

        //老韩的需要先手动调一下,我的不用,我的实现直接循环就可以了。
        //先手动调用一下scan,将minDis生成一下。
//        scan(start);

        while (true){
            int minDisSub = getMinDisSub();
            if(minDisSub != -1){
                scan(minDisSub);
            }else break;
        }

    }

    /**
     * 调用scan的方法,即不断从最小值表中得到最小值,然后放入scan方法中
     * 如果没有最小值,或者已经全部遍历过了,返回-1;
     *
     * 实际上可以用优先队列来实现这个结构,毕竟该函数目的就是为了弹出一个最小值罢了
     */
    public int getMinDisSub(){
        int minDistance = 1000;
        int sub = -1;
        for (int i = 0; i < minDis.length; i++) {
            if(check[i] == 0 && minDis[i] < minDistance){
                minDistance = minDis[i];
                sub = i;
            }
        }
        return sub;
    }

    /**
     * 扫描sub结点,找出所有与sub结点连接的点,按照要求对该点进行判断,判断成功则更新该点minDis,失败则跳过
     * 如果判断成功,将该点距离加入最小指标,修改该点痕迹表,以及为该点重新设置前驱表,
     * 如果判断失败,跳过修改步骤,结束方法
     * 判断方法的内容为:
     * 1.设与sub点连接的点为v,v距离v0的距离是否小于最小值表中v距离v0的距离。具体如下:
     * sub距离v的最小距离为sub-v,v0到sub的最小距离为minDis[sub],v0到v的最小距离(原)为minDis[v],
     * 判断(sub-v)+minDis[sub] < minDis[v],是否成立,如果成立,即判断成功,如果不成立,即判断失败。
     *
     * @param sub
     */
    public void scan(int sub) {
        //能够进入这个方法,就说明该点已经是目前最短的点了,因此把该点的check设为1也是正常的。
        // 不管后续会不会有修改,这是第一次确定该点为最短的时候,如果后续有修改,那是后续的事情了,与该点是否到达无关
        check[sub] = 1;
        for (int i = 0; i < edges.length; i++) {
            //先把所有和sub点相邻的点的左边放进去判断一下,为了节约时间,只和没走过的点判断
            if(check[i] == 0){
                //进入判断方法
                minDisUpdate(sub, i, edges[sub][i]);
            }
        }
    }

    /**
     * 判断方法,具体描述写在了scan方法上面
     * @param startSub 源点
     * @param minWeightSub 终点
     * @param weight 两点间的权值
     */
    private void minDisUpdate(int startSub, int minWeightSub, int weight) {
        //如果小于原值,那么就更新值,并且更新前驱表
        //和原来的值比较,如果大于原来的值,就跳过了
        if (minDis[minWeightSub] > weight + minDis[startSub]) {
            minDis[minWeightSub] = weight + minDis[startSub];
            preVertex[minWeightSub] = startSub;
        }
    }

}

acwing上面实现的dijkstra算法,算是个模板,我修改了一点,可读性高了点,容易背:

import java.util.*;

/**
 * @desc 使用acwing(oj)用的模板
 */
public class Main {
    
    //定义容器、常数、读入
    int N = 510;
    int M = 100010;
    int[][] g = new int[N][N];//邻接矩阵
    boolean st[] = new boolean[N];
    int[] dis = new int[N];
    Scanner jin = new Scanner(System.in);
    int n,m;
    
    //oj要用的main方法
    public static void main(String[] args) {new Main().run();}//在oj中调用题解方法

    void run() {
        
        //读入题目数据
        n = jin.nextInt();
        m = jin.nextInt();
         //dis数组、邻接表预处理
        for(int i = 1; i <= n; i++){
            dis[i] = M;
            for(int j = 1; j <= n; j++){
                g[i][j] = M;//无穷
            }
        }
        
        for (int i = 0; i < m; i++) {//麻了,这里竟然有bug,输入没搞明白。。草
            int a = jin.nextInt();
            int b = jin.nextInt();
            int c = jin.nextInt();
            g[a][b] = Math.min(g[a][b],c);//去除重边
        }
        
        //调用解题方法
        int ans = dijkstra();
        
        //输出题解答案
        System.out.print(ans);
    }
    
    int dijkstra(){
        // Arrays.fill(dis, 0x3f3f);
        dis[1] = 0;
        
        for(int i = 0; i < n; i++){//从1开始探索寻找最短边
            
            //寻找S集合中的最短点,设t点为最小点
            boolean flag = false;//是否寻找到了点集中的一个点
            int t = -1;
            for(int j = 1; j <= n; j++ ){//每次探索都要从1开始,直到n结束
                if(!st[j]){//如果符合要求
                    if(!flag) {
                        t = j;
                        flag = true;
                    }
                    if(flag && (dis[t] > dis[j])) t = j;
                }
            }
            
            st[t] = true;//必定有一个t是在这里的,这是dijkstra算法的理论,不需要自己证明
            
            for(int j = 1; j <= n; j++){//从t出发,寻找dis[t]+g[t][j]最小值;更新dis表
                dis[j] = Math.min(dis[j], dis[t] + g[t][j]);
            }

        }
        if(dis[n] == M) return -1;
        else return dis[n];
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值