求所有最短路径的Dijkstra算法(JAVA)实现

本文介绍了Dijkstra算法的基本思想,详细展示了算法的Java实现过程,并通过一个设备更新问题来具体分析算法的应用。文章还讨论了算法的验证、可能存在的问题以及使用HashMap改进算法的方法。

目录

前言:

Dijkstra算法实现:

Dijkstra算法介绍:

Dijkstra算法Java实现:

Dijkstra算法分析:

Dijkstra算法验证:

Dijkstra算法改进:

结语:


前言:

Dijkstra算法是经典的图论算法,用于求得某个固定起点到任意顶点的最短路径。下面介绍一下经典的Dijkstra算法的java实现过程,而后引出问题,改进算法解决我们提出的问题。

Dijkstra算法实现:

Dijkstra算法介绍:

1.算法目的:在给出顶点集和邻接矩阵的图G中求出固定起点的顶点到其余顶点的最短路径。在算法中,定义五个集:

visited 顶点访问集合,记录了某个顶点是否已经被访问过,访问过则返回1,没有访问过为0。集合的大小等于顶点集的个数
   dis 距离集合,记录起点顶点各个顶点之间的最小距离,最后输出该集合。集合的大小等于顶点集的个数。起点顶点到自身的距离为0
pre 前驱节点记录集合,用于记录某个访问顶点的前驱节点,表示该顶点是通过某个前驱节点指向的,通过这个集合我们可以追溯路径,集合的大小等于顶点集的个数
martex 邻接矩阵。用于表示图,是一个二维数组
vertex 顶点集合。

 

2.具体实现步骤:

  1. 初始化三个集合。将dis集合中,将全部值置为无穷大,表示目前没有任何两个顶点可以连通,pre集合的所有值置为0,visited所有值置为0。
  2. 获得出发顶点V(i),将顶点V对应的visited(i)值置为1,pre(i)值置为0,从dis集合中取出dis(i)的值,(对于出发顶点而言,这个值肯定是0),从martex中获得出发顶点到其余顶点,(例如j顶点)的距离,如果dis(i)+martex(i)(j)<dis(j),那么将dis集合中对应的dis(j)的值置为dis(i)+martex(i)(j),然后依次移动j的位置到最后一个顶点。第一轮赋值完成。
  3. 在dis数组中查找到最小的一个值对应的顶点(例如k),将该顶点对应的visited集合中的值置为1,然后取出dis(k)的值,将未访问的节点在依次进行访问(例如h),取出martex(k)(h)的值,如果dis(k)+martex(k)(h)<dis(h),那么更新dis集合中dis(h)的值,更新pre集合中pre(h)的值为k,表示起点到h的距离是通过k节点连接的。
  4. 重复3步骤,直到visited集合中的所有值置为1停止。输出dis集合和pre集合。

3.读懂dis集合和pre集合。

举一个例子:有六个顶点的图,将邻接矩阵经过dijkstra算法计算后,得到输出的dis集合,pre集合如下:

dis [0,5,7,12,17,19]
pre [1,1,2,3,4,5]

 

例如我们要找到V1-V6的最短距离,从dis中的dis(6)=19即可得出。那么V1是怎么走到V6的呢? 我们可以看pre集合。

pre(6)=5,表示V6的前驱节点是V5,我们于是找到pre(5)=4,表示V5的前驱节点是V4,然后我们再找到pre(4)=3,表示V4是通过V3找到的。如此下去,我们发现pre(2)=1,也就是说V2是通过V1找到的。V1前面没有前驱节点了(这里=1就表示是它本身),我们将这个寻找的过程倒着回去,就得到答案:1-2-3-4-5-6 ,就是V1-V6的最短路径,最短的值是19.

 

如果没有看懂上面的算法实现流程也没关系,可以去看Dijkstra算法分析中的具体问题的实现步骤,这样会对算法有更好的了解。

Dijkstra算法Java实现:

基于上面提到的思路分析,将思路用代码实现如下:

1.构建图类:

class Graph{
    private String[] vertex;//顶点数组
    private int[][] matrix;//邻接矩阵
    private  VisitedVertex vv;//实现Dijkstra算法时的存放数据的类。
    public Graph(String[] vertex,int[][] matrix){
        this.vertex=vertex;
        this.matrix=matrix;
    }
  /**
     * @param index 从哪个顶点开始(起点)
     *
     * */
    public void dsj(int index){
        vv=  new VisitedVertex(vertex.length,index);
        update(index);//更新index顶点到周围顶点的距离
        for (int j=1;j<vertex.length;j++){
            index=vv.updateArr();//返回新的访问顶点
            update(index);
        }
        vv.show();
    }
    //更新index下标顶点到周围顶点的距离和周围顶点的前驱节点
    public void update(int index){
        int len=0;
        for(int j=0;j<matrix[index].length;j++){
            //len是出发顶点到index顶点的距离+从index顶点到j顶点的距离的和
            len=vv.getDis(index)+matrix[index][j];
            //如果j顶点没有被访问过,并且len小于出发顶点到j顶点的距离,就需要更新
            if(!vv.in(j)&&len<vv.getDis(j)){
                vv.updatePre(j,index);
                vv.updateDis(j,len);
            }
        }
    }

}

 2.构建VisitedVertex类:

class VisitedVertex{
    public int[] already_arr;//已经访问过的顶点集合
    public int[] pre_visited;//顶点的前驱节点
    public int[] dis;//距离记录数组


    /**
     *
     * @param length 顶点的个数
     * @param index 访问的起点
     */
    public VisitedVertex(int length,int index){
        this.already_arr=new int[length];
        this.pre_visited=new int[length];
        this.dis=new int[length];
        Arrays.fill(dis,Short.MAX_VALUE);
        this.already_arr[index]=1;
        this.dis[index]=0;
    }

    /**
     *
     * @param index 判断顶点是否被访问过
     * @return 访问过就返回true
     */
    public boolean in(int index){
        return already_arr[index]==1;
    }

    /**
     * 更新出发顶点到index顶点的距离
     * @param index index顶点
     * @param len 出发点到该顶点的距离
     */
    public  void updateDis(int index,int len){
        dis[index]=len;
    }

    
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值