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(); } }