Dijkstra算法求解最短路径问题(java代码实现)

本文深入讲解了Dijkstra算法在无向图和有向图中的应用,通过Java代码实现了求解最短路径问题的过程,详细展示了算法步骤和最终的路径结果。

Dijkstra算法求解最短路径问题(java代码实现)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

java代码实现
package com.bingym.dijkstra;

import java.util.Arrays;

public class DijkstraAlgorithmNoDirectedGraph {
    /*
    * 利用Dijkstra算法求解最短路径问题
    * 此时为无向图,顶点分别为:'A', 'B', 'C', 'D', 'E', 'F', 'G'七个顶点
    * 求解每个顶点到其他所有顶点的最短路径
    * 其中:N表示无法到达:下面包括到达自身(无法到达自身顶点)
    * 'A'到其他顶点的距离为:{N,5,7,N,N,N,2};
    * 'B'到其他顶点的距离为:{5,N,N,9,N,N,3};
    * 'C'到其他顶点的距离为:{7,N,N,N,8,N,N};
    * 'D'到其他顶点的距离为:{N,9,N,N,N,4,N};
    * 'E'到其他顶点的距离为:{N,N,8,N,N,5,4};
    * 'F'到其他顶点的距离为:{N,N,N,4,5,N,6};
    * 'G'到其他顶点的距离为:{2,3,N,N,4,6,N};
    * */
    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 = 65535;// 表示不可以连接(最大值)
        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对象
        Graph graph = new Graph(vertex, matrix);
        //测试无向图是否创建成功
        System.out.println("此时A,B,C,D,E,F,G七个顶点构成的无向图如下所示:");
        graph.showGraph();
        //测试Dijkstra算法
        int startIndex = 2;
        graph.dijkstra(startIndex);
        graph.showDijkstra(startIndex);

    }
}

//定义一个无向图:将顶点以及顶点之间的距离(用邻接矩阵表示)
class Graph {
    //定义无向图的需要的属性:顶点集合,邻接矩阵,以及已经访问的顶点的集合(VisitedVertexArr)
    private char[] vertex;//保存顶点的数组
    private int[][] matrix;//邻接矩阵的二维数组
    //已经访问的顶点的集合
    private VisitedVertex vv;

    //定义图的构造器
    public Graph(char[] vertex, int[][] matrix) {
        this.vertex = vertex;
        this.matrix = matrix;
    }

    //定义该无向图的api
    //方法1:显示无向图的邻接矩阵
    public void showGraph() {
        for (int[] link : matrix) {
            System.out.println(Arrays.toString(link));
        }
    }

    //方法2:更新index下标的顶点到周围顶点的距离以及周围顶点的前驱顶点
    private void update(int index) {
        int len = 0;
        //根据遍历我们的邻接矩阵对应的index行的得到index到其他顶点的距离
        for (int j = 0; j < matrix[index].length; j++) {
            //此时我们需要计算出发顶点到index顶点的距离 + index顶点到其他顶点(j)的距离之和
            len = vv.getDis(index) + matrix[index][j];
            if (!vv.isVisited(j) && len < vv.getDis(j)) {
                //如果j顶点还未访问过,并且len小于出发顶点到j的距离,我们就进行出发顶点到j顶点的新方案的更新
                vv.updatePre(j,index);
                vv.updateDis(j,len);
            }
        }
    }

    //方法3:Dijkstra算法
    public void dijkstra(int index) {
        //int count = 0;
        vv = new VisitedVertex(vertex.length,index);//vertex.length为顶点的个数,index为开始的顶点
        //vv.path[0] = vertex[index];
        update(index);//更新index顶点:目前为起始顶点到周围顶点的距离,以及更新前驱顶点
        for (int j = 1; j < vertex.length; j++) {
            //记录新的访问顶点,并更新index顶点到周围顶点的距离以及前驱顶点
            index = vv.updateArr();//选择并返回新的访问顶点
            //vv.path[++count] = vertex[index];
            update(index);//然后更新新的index,直到所有顶点都访问完,即找到起始顶点到其他顶点的最短路径
        }
    }

    public void showDijkstra(int index) {//index表示开始的顶点
        vv.show(index);;
    }
}

//定义已访问的顶点的集合类
class VisitedVertex {
    //定义属性:
    //1.记录各个顶点是否已经访问过:1表示已经访问过,0表示仍未访问
    public int[] isVisited;
    //2.记录每一顶点在达到最短路径的前一个顶点:即每一个顶点的前驱顶点
    public int[] preVisited;
    //3.记录出发顶点到其他所有顶点的最短距离:
    public int[] dis;
    //4.记录实现最短路径的路径
    //public char[] path;

    //定义构造器
    //vertexNum:表示顶点的个数;index表示出发顶点的下标
    public VisitedVertex(int vertexNum,int index) {
        this.isVisited = new int[vertexNum];
        this.preVisited = new int[vertexNum];
        this.dis = new int[vertexNum];
        //this.path = new char[vertexNum];

        //初始化dis数组
        Arrays.fill(dis,65535);//将dis初始化为65535:最大值
        this.isVisited[index] = 1;//将出发顶点设置为被访问过
        this.dis[index] = 0;//设置出发顶点到自身的访问距离为0
    }

    //定义api
    //方法1:判断index下标的顶点是否访问过
    //若访问过,返回true;若未访问,返回false
    public boolean isVisited(int index) {
        return isVisited[index] == 1;//即该数组对应下标数值是否为1
    }

    //方法2:更新出发顶点到index顶点的距离
    public void updateDis(int index,int len) {
        dis[index] = len;
    }

    //方法3.更新此时距离index下标顶点最短路径的顶点pre为index顶点的的前驱顶点
    public void updatePre(int pre,int index) {
        preVisited[pre] = index;
    }

    //方法4:返回出发顶点到index顶点的距离
    public int getDis(int index) {
        return dis[index];
    }

    //方法5:继续选择并返回新的访问顶点
    public int updateArr() {
        int min = 65535;
        int index = 0;
        for (int i = 0; i < isVisited.length; i++) {
            if (isVisited[i] == 0 && dis[i] < min) {
                min = dis[i];
                index = i;
            }
        }
        //更新index顶点为已经访问过
        isVisited[index] = 1;
        return index;
    }

    //方法6:显示最后的最短路径结果
    public void show(int index) {
        char[] vertex = { 'A', 'B', 'C', 'D', 'E', 'F', 'G' };
        int count = 0;
        System.out.println(vertex[index] + "顶点到下面顶点的最短路径为:");
        for (int i : dis) {
            if (i != 65535) {
                System.out.print(vertex[count] + "(" + i + ") ");
            } else {
                System.out.println("N");
            }
            count++;
        }
        System.out.println();

        /*count = 1;
        while(count < path.length) {
            System.out.println("顶点" + path[0] + "到顶点" + path[count] + "最短路径为: ");
            for (int i = 0; i <= count; i++) {
                System.out.print(path[i] + "->");
            }
            count++;
            System.out.println();
        }*/

    }
}

输出结果:
此时A,B,C,D,E,F,G七个顶点构成的无向图如下所示:
[65535, 5, 7, 65535, 65535, 65535, 2]
[5, 65535, 65535, 9, 65535, 65535, 3]
[7, 65535, 65535, 65535, 8, 65535, 65535]
[65535, 9, 65535, 65535, 65535, 4, 65535]
[65535, 65535, 8, 65535, 65535, 5, 4]
[65535, 65535, 65535, 4, 5, 65535, 6]
[2, 3, 65535, 65535, 4, 6, 65535]
C顶点到下面顶点的最短路径为:
A(7) B(12) C(0) D(17) E(8) F(13) G(9

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

java代码实现
package com.bingym.dijkstra;

import java.util.ArrayList;
import java.util.List;

public class DijkstraAlgorithmDirectedGraph {
    /*
    * Dijkstra算法求解有向图的最短路径问题
    * 存在顶点1~6,构成有向图:
    * 要求:求解顶点1到其他五个顶点的最短路径
    *
    * */
    //主函数
    public static void main(String[] args) {
        //构建顶点以及顶点间距离的数组,其中若相邻的顶点之间没有路径,则设置其距离为100
        int len[][] = new int[7][];
        //第一行和第一列均为0:不使用,使得顶点的编号和数组的下标能够对上
        len[0] = new int[] {0,0,0,0,0,0,0};
        len[1] = new int[] {0,0,9,4,100,100,100};
        len[2] = new int[] {0,100,0,100,12,5,100};
        len[3] = new int[] {0,100,4,0,100,13,100};
        len[4] = new int[] {0,100,100,100,0,100,2};
        len[5] = new int[] {0,100,100,100,3,0,15};
        len[6] = new int[] {0,100,100,100,100,100,0};
        //确定顶点的个数
        int num = 6;
        int dis[] = new int[num + 1];
        //dis数组用于存储1顶点到各个顶点的最短距离,先根据有向图存入初始值
        for(int j =0;j < len.length;j++) {
            dis[j] = len[1][j];
        }

        //利用Dijkstra算法查找1顶点到各个顶点的最短路径的函数方法
        findMinPath(len,dis,num);

    }

    //Dijkstra算法实现查找每两个顶点之间最短距离的函数
    private static void findMinPath(int[][] len, int[] dis, int n) {
        //定义一个标记flag
        int flag = 1;  //表示第一个顶点
        int biaoJi[] = new int[n + 1];  //n+1=7 {空出第biaoJi[0],只使用biaoJi[1]~biaoJi[6]使得顶点的数字和数组的下标对应上}
        //定义一个存储最短路径顶点的集合
        List<Integer> list = new ArrayList<Integer>();
        list.add(flag);//将顶点1加入最短路径集合
        biaoJi[flag] = 1;   //先将顶点1标记,相当于将1顶点加入X集合,其余2-6顶点未标记1,加入Y集合
        //Dijkstra算法实现
        for(int i = 2;i <= n;i++) {//从第二个顶点(即顶点2)开始遍历
            //定义Integer.MAX_VALUE,作为路径距离的最小值参考值
            int min = Integer.MAX_VALUE;
            for(int j = 1;j <= n;j++) {
                if(biaoJi[j] == 0 && min >= dis[j]) {
                    min = dis[j];
                    flag = j;
                }
            }
            //将新增的最短路径的顶点加入到集合X中,即令其biaoJi[flag] = 1,达到X集合增加,Y集合减少的结果;
            biaoJi[flag] = 1;
            //将最短路径的顶点添加到最短路径顶点集合中
            list.add(flag);
            for(int k = 1;k <= n;k++) {
                dis[k] = minDis(dis[flag] + len[flag][k],dis[k]);
            }
            //System.out.println("1顶点到" + flag + "顶点的最短路径距离是" + dis[flag]);
        }

        //输出打印顶点1到其他顶点的最短距离和最短路径
        int count = 1;
        while(count < 6) {
            System.out.println("1顶点到" + list.get(count) + "顶点的最短路径为:" + dis[list.get(count)]);
            for (int i = 0;i <= count;i++) {
                if(i != count) {
                    System.out.print(list.get(i) + ">>");
                }else {
                    System.out.print(list.get(i));
                }
            }
            System.out.println("");
            count++;
        }

    }

    //求最小值并返回其最小值的函数
    private static int minDis(int i, int j) {
        return (i<=j) ? i : j;
    }
}

输出结果:
1顶点到3顶点的最短路径为:4
1>>3
1顶点到2顶点的最短路径为:8
1>>3>>2
1顶点到5顶点的最短路径为:13
1>>3>>2>>5
1顶点到4顶点的最短路径为:16
1>>3>>2>>5>>4
1顶点到6顶点的最短路径为:18
1>>3>>2>>5>>4>>6
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值