0
点赞
收藏
分享

微信扫一扫

Java数据结构---Dijkstra求最短路径

boom莎卡拉卡 2022-02-17 阅读 52

运行效果如下
在这里插入图片描述
源代码如图,注释已经很多了,如果还有点偏差的话可以看《大话数据结构》的迪杰斯特拉讲解部分

package algorithm.DataStruct.Frequentlyused.ShortestPath.Dijkstra;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;

/**
 * @author: Serendipity
 * Date: 2022/2/16 20:37
 * Description:迪杰斯特拉算法用于求最短路径问题
 * 例如两个点,如何到达能采与最短的路径 底层使用广度优先BFS
 * 迪杰斯特拉(Dijkstra)算法过程
 * 设置出发顶点为v,顶点集合V{v1,v2,vi...},v到v中各顶点的距离构成距离集合Dis,Dis{d1,d2,di...},
 * Dis集合记录着v到图中各顶点的距离(到自身可以看作0, v到vi距离对应为di)
 * 1)从Dis中选择值最小的di并移出Dis集合,同时移出V集合中对应的顶点vi,此时的
 * v到vi即为最短路径
 * 2)更新Dis集合,更新规则为:比较v到V集合中顶点的距离值,与v通过vi到V集合
 * 中顶点的距离值,保留值较小的一个(同时也应该更新顶点的前驱节点为vi,表明是通过vi到达的)
 * 3)重复执行两步骤,直到最短路径顶点为目标顶点即可结束
 */
public class Dijkstra {
    public static void main(String[] args) {
        char[] vertex = {'0', '1', '2', '3', '4', '5', '6', '7', '8'};
        //邻接矩阵
        int[][] matrix = new int[vertex.length][vertex.length];
        final int N = 65535;// 表示不可以连接
        matrix[0] = new int[]{0, 1, 5, N, N, N, N, N, N};
        matrix[1] = new int[]{1, 0, 3, 7, 5, N, N, N, N};
        matrix[2] = new int[]{5, 3, 0, N, 1, 7, N, N, N};
        matrix[3] = new int[]{N, 7, N, 0, 2, N, 3, N, N};
        matrix[4] = new int[]{N, 5, 1, 2, 0, 3, 6, 9, N};
        matrix[5] = new int[]{N, N, 7, N, 3, 0, N, 5, N};
        matrix[6] = new int[]{N, N, N, 3, 6, N, 0, 2, 7};
        matrix[7] = new int[]{N, N, N, N, 9, 5, 2, 0, 4};
        matrix[8] = new int[]{N, N, N, N, N, N, 7, 0, 4};
        //创建 Graph对象
        Graph graph = new Graph(vertex, matrix);
        //测试, 看看图的邻接矩阵是否ok
        graph.showMatrix();
        graph.Dijkstra_ShortestPath(0);
        graph.showShortPathTable();
        graph.showShortPathMatrix();
        graph.showToShortestPath();
    }
}
//图类
class Graph {
    private char[] vertex;
    private int[][] matrix;
    private int[] ShortestPathMatrix;   //用于存储最短路径下标的数组 [0,0,1,2]->表示0->0自己到自己 1->表示从0直接到1最近
    private int[] ShortestWeightTable;   //用于存储到各店最短路径的权值和 //2表示从1到更近,然后1由0直接到 所以2的路径为0->1->2

    public Graph(char[] vertex, int[][] matrix) {
        this.matrix = matrix;
        this.vertex = vertex;
        ShortestPathMatrix = new int[vertex.length];
        ShortestWeightTable = new int[vertex.length];
    }

    /**
     * 显示矩阵
     */
    public void showMatrix() {
        System.out.println("各顶点间关系权值图如下:");
        for (int[] ints : this.matrix) {
            System.out.println(Arrays.toString(ints));
        }
    }

    public void showShortPathTable() {
        System.out.print("到达各点的路径为:");
        System.out.println(Arrays.toString(ShortestWeightTable));
    }

    public void showShortPathMatrix() {
        System.out.print("到达各点的权值为:");
        System.out.println(Arrays.toString(ShortestPathMatrix));
    }

    /**
     * 该函数用于显示到达每一个顶点的路径
     * 路径用每一个顶点再数组中的下标表示
     * 例如第一个数据'0'的下标就是0以此类推
     */
    public void showToShortestPath() {
        HashMap<Character, ArrayList<String>> map = new HashMap<>();
        for (int i = 0; i < vertex.length; i++) {//遍历所有的顶点
            ArrayList<String> list = new ArrayList<>();//创建一个用于存放路径的List
            getList(i,list);//向顶点中添加路过的顶点
            Collections.reverse(list);//反转顶点 这是由于添加是倒序添加的
            map.put((char)(i+48),list);//这个随意写 为了好看而已
        }
        int index=0;
        for (Character character : map.keySet()) {//输出
            System.out.println("到达v"+character+"的最短路径是"+map.get(character)
            +"其权值为"+ShortestWeightTable[index++]);
        }
    }

    /**
     * 使用递归的方法向list中添加顶点所路过的顶点
     * @param start 开始顶点对应的数组下标
     * @param list 需要添加路径的list集合
     */
    public void getList(int start,ArrayList<String>list){
        if(start==0){ //遇到开始顶点0直接退出并且加入开始顶点
            list.add(vertex[0]+""); //添加起始路径0
           return; //已经到达源点 那么退出
        }else{
            list.add(vertex[start]+""); //不是源点 那么把当前路径添加到list中
            getList(ShortestPathMatrix[start],list); //然后继续递归添加
        }
    }
    public void Dijkstra_ShortestPath(int startVertex) {
        int v, w, k = 0, min;
        boolean isFind[] = new boolean[vertex.length];//定义已经找到最短路径的顶点数组
        isFind[startVertex] = true;//开始的顶点那么直接就是最短路径0
        for (v = 0; v < vertex.length; v++) {//初始化与初始移动的顶点连接的边的权值
            ShortestWeightTable[v] = this.matrix[startVertex][v];//初始化权值之后才能决定如何从起始点往那个位置出发
        } //这个数组记录源点到某个顶点的最小距离
        ShortestWeightTable[startVertex] = 0; //开始顶点到开始顶点的距离为0
        //每次循环球的起始顶点与一个顶点的最短路径由于抛去了起始顶点,因此v从1开始
        for (v = 1; v < this.vertex.length; v++) {//遍历所有顶点 求得开始顶点到每个顶点的最短距离
            min = Integer.MAX_VALUE;//暂时设置为MAX便于得到更小的值
            for (w = 0; w < vertex.length; w++) {
                if (!isFind[w] && ShortestWeightTable[w] < min) {//最小距离数组的数据<min上一次的最小数据
                    k = w; //那么就把当前更小的数据的位置记录 k用于记录这一次循环中得到的最小的数据
                    min = ShortestWeightTable[w];//w顶点对应的权值离开始顶点更近
                }
            }
            isFind[k] = true;//找到最短路径,设置为true
            for (w = 0; w < vertex.length; w++) {
                //如果经过v顶点的路径比经过现在这条更短的话
                //这一步算法的意思是先判断当前顶点是否已经有了最短路径,如果没有
                //由于k是刚才新找到的已经得到最短路径的顶点对应的下标
                //因此min+this.matrix[k][w]表示的是基于上一个顶点走到这个顶点距离更短
                //还是从顶点直接走到她更短
                //举个例子 例如v0->v1=1,v0->v2=5,v1->v2=3,那么明显v0->v1->v2=4<5
                //因此我们从这个新节点(v1)走到这个v2距离更短
                //那么我们就应该选择这条路加进去,而下面这个if判断就是怎么做的
                //他先判断v2顶点还没找到最短路径,那么我们就试着通过v1->v2(this.matrix[k][w])+v0->v1(min)
                //判断它是不是小于目前到达这个顶点的路径长度 如果是那么我们就更新
                if (!isFind[w] && (min + this.matrix[k][w] < ShortestWeightTable[w])) {
                    //找到了更短的路径,修改
                    ShortestWeightTable[w] = min + this.matrix[k][w];
                    ShortestPathMatrix[w] = k; //说明到达这个顶点通过k这个顶点会更快
                }
            }
        }
    }
}

举报

相关推荐

0 条评论