Dijkstra算法与最短路径问题

@author:QYX 最近两三个周,肝完了一个开源项目,看完了webkit技术内幕和Devlops的书,收获不错

继续搬运更新!

迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径。
它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止

基本思想
通过Dijkstra计算图G中的最短路径时,需要指定起点s(即从顶点s开始计算)。

此外,引进两个集合S和U。S的作用是记录已求出最短路径的顶点(以及相应的最短路径长度),而U则是记录还未求出最短路径的顶点(以及该顶点到起点s的距离)。

初始时,S中只有起点s;U中是除s之外的顶点,并且U中顶点的路径是”起点s到该顶点的路径”。然后,从U中找出路径最短的顶点,并将其加入到S中;接着,更新U中的顶点和顶点对应的路径。 然后,再从U中找出路径最短的顶点,并将其加入到S中;接着,更新U中的顶点和顶点对应的路径。 … 重复该操作,直到遍历完所有顶点。

操作步骤
初始时,S只包含起点s;U包含除s外的其他顶点,且U中顶点的距离为”起点s到该顶点的距离”[例如,U中顶点v的距离为(s,v)的长度,然后s和v不相邻,则v的距离为∞]。

从U中选出”距离最短的顶点k”,并将顶点k加入到S中;同时,从U中移除顶点k。

更新U中各个顶点到起点s的距离。之所以更新U中顶点的距离,是由于上一步中确定了k是求出最短路径的顶点,从而可以利用k来更新其它顶点的距离;例如,(s,v)的距离可能大于(s,k)+(k,v)的距离。

重复步骤(2)和(3),直到遍历完所有顶点。

 

 

 

 

 

 

 

 

 

 

 

 

package com.qyx.Tree;

import java.util.Arrays;

public class DijkstraAlgorithm {
    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=new Graph(vertex,matrix);
        graph.showGraph();
        graph.dsj(6);
        graph.show();
    }
}
class Graph{
    private char[] vertex;//顶点数组
    private int[][] matrix;//邻接矩阵
    private VisitedVertex vv;//已经访问的顶点集合
    public void show()
    {
        vv.show();
    }
    //构造器
    public Graph(char[] vertex,int[][] matrix)
    {
        this.vertex=vertex;
        this.matrix=matrix;
    }
    //显示图
    public void showGraph()
    {
        for(int link[]:matrix)
        {
            System.out.println(Arrays.toString(link));
        }
    }
    //迪杰斯特拉算法那实现
    /**
     * 
     * @param index 表示出发节点对应下标
     */
    public void dsj(int index)
    {
        vv=new VisitedVertex(vertex.length, index);
        update(index);
        for(int j=1;j<vertex.length;j++)
        {
            index=vv.updateArr();//选择并返回新的访问节点
            update(index);//更新index下标顶点到周围顶点的距离和周围顶点的前驱顶点
        }
    }
    //更新index下标顶点到周围顶点的距离和周围顶点的前驱顶点
    private void update(int index)
    {
        int len=0;
        //根据遍历我们的邻接矩阵的matrix[index]行
        for(int j=0;j<matrix[index].length;j++)
        {
            //len的含义是出发顶点到index顶点的距离+从index顶点到j顶点的距离的和
            len=vv.getDis(index)+matrix[index][j];
            //如果j顶点没有被访问过,并且len小于出发顶点到j顶点的距离就需要更新 G->A->B
            if(!vv.in(j)&&len<vv.getDis(j))
            {
                vv.updatePre(j, index);//更新j顶点的前驱为index顶点
                vv.updateDis(j, len);//更新出发顶点到j顶点的距离
            }
        }
    }
}
//已访问顶点集合
class VisitedVertex{
    
    //记录各个顶点是否被访问过,1表示访问过,0表示未访问,会动态更新
    public int[] aleady_arr;
    //每个下标对应的值的前一个顶点下标,会动态更新
    public int[] pre_visited;
    //记录出发顶点到其他所有顶点的距离,比如G为出发顶点,就会记录G到其他顶点距离,会动态更新,求得最短距离就会存放到dis
    public int[] dis;
    //构造器
    /**
     * 
     * @param length 表示顶点个数
     * @param index 表示出发顶点对应的下标,比如G顶点,下标就是6
     */
    public VisitedVertex(int length,int index)
    {
        this.aleady_arr=new int[length];
        this.pre_visited=new int[length];
        this.dis=new int[length];
        //初始化dis数组
        Arrays.fill(dis,65535);
        this.aleady_arr[index]=1;//设置出发顶点被访问过
        this.dis[index]=0;//设置出发顶点的访问距离为0
    }
    /**
     * 功能:判断index顶点是否被访问过
     * @param index 
     * @return 如果访问过就返回true,否则返回false
     */
    public boolean in(int index)
    {
        return aleady_arr[index]==1;
    }
    /**
     * 功能:更新出发顶点到index顶点的距离
     * @param index 
     * @param len
     */
    public void updateDis(int index,int len)
    {
        dis[index]=len;
    }
    /**
     * 功能:更新顶点的前驱为index结点
     * @param pre
     * @param index
     */
    public void updatePre(int pre,int index)
    {
        pre_visited[pre]=index;
    }
    /**
     * 返回出顶定点到index顶点的距离
     * @param index
     * @return 
     */
    public int getDis(int index)
    {
        return dis[index];
    }
    //继续选择并返回新的访问顶点,比如这里的G访问完后,就是A点作为新的访问顶点(注意不是出发顶点)
        public int updateArr()
        {
            int min=65535,index=0;
            for(int i=0;i<aleady_arr.length;i++)
            {
                if(aleady_arr[i]==0 && dis[i]<min)
                {
                    min=dis[i];
                    index=i;
                }
            }
            aleady_arr[index]=1;
            return index;
        }
    //显示最后的结果
    //即将三个数组输出
        public void show()
        {
            System.out.println("================================");
            for(int i : aleady_arr)
            {
                System.out.print(i+" ");
            }
            System.out.println();
            for(int i:pre_visited)
            {
                System.out.print(i+" ");
            }
            System.out.println();
            for(int i:dis)
            {
                System.out.print(i+" ");
            }
            System.out.println();
            char[] vertex={'A','B','C','D','E','F','G'};
            int count=0;
            for(int i:dis)
            {
                if(i!=65535)
                {
                    System.out.print(vertex[count]+"("+i+")");
                }
                count++;
            }
            System.out.println();
        }
}

 

posted @ 2020-03-16 21:05  计算机的探索者  阅读(468)  评论(0编辑  收藏  举报