给定带权有向图G和源点v, 求从v到G中其余各顶点的最短路径。
Dijkstra算法:
Dijkstra提出了一个按路径“长度”递增的次序,逐步得到由给定源点到图的其余各点间的最短路径的算法:
假设我们以邻接矩阵cost(代码中为A[ ]数组),表示所研究的有向网的代价矩阵。
迪杰斯特拉算法需要一个顶点集合,初始时集合内只有一个源点V0 ,以后陆续将已求得最短路径的顶点加入到集合中,到全部顶点都进入集合了,过程就结束了。集合 可用一维数组来表示,设此数组为S(代码中为mark[ ]数组),凡在集合S以外的顶点,其相应的数组元素S[i] 为 -1 ,否则为 1 。
另需一个一维数组D(代码中为dis[ ]数组),每个顶点对应数组的一个单元,记录从源点到其他各顶点当前的最短路径长度,其初值为D[i]=cost[V0][i],i=1…n。数组D中的数据随着算法的逐步进行要不断地修改
定义了S集合和D数组并对其初始化后,迪杰斯特拉算法在进行中,都是从S之外的顶点集合中选出一个顶点w,使D[w]的值最小。于是从源点到达w只通过S中的顶点,把 w 加入集合S中,并调整D中记录的从源点到集合中每个顶点v的距离: 取D[v]和D[w]+cost[w][v]中值较小的作为新的D[v]
重复上述,直到S中包含V中其余各顶点的最短路径。
实例:
代码及解析:
package utils; import java.io.File; public class ShortestPath { static int INF = Global.INF; public static void dijkstraShortestPath(int v,int[][] A){ int n = A[0].length; int[] dis = new int[n]; int[] path = new int[n]; int[] mark = new int[n]; for(int i=0;i<n;i++){ dis[i] = A[v][i]; path[i] = v; mark[i] = -1; } mark[v] = 1; dis[v] = 0; int k = v; for(int i =1 ; i<n;i++){ //考察剩余的n-1个节点 int min = Global.INF; for(int j = 0;j<n;j++){//找出本轮对应路径最短的节点 if((mark[j]!=1)&&(dis[j]<min)){ min = dis[j]; k = j; } } mark[k] = 1;//将找出的最短路径对应的节点k加入集合S中 for(int j =0;j<n;j++){//用上面新加入的节点k来更新dis[] if((mark[j]!=1)&&(A[k][j]<Global.INF)&&(min+A[k][j]<dis[j])){//不加A[k][j]<Global.INF的话,如果A[k][j]=Global.INF //min+A[k][j]就会得到一个很大的负数使得<dis[j]成立使程序出错 dis[j] = min+A[k][j]; path[j] = k ; } } } //打印 for(int i =0;i<n;i++){ if(i!=v){ System.out.print("v"+v+"到v"+i+"的最短距离为:"); if(mark[i]!=1){//if(!(dis[i]<Global.INF)){// //System.out.print("无"); System.out.print("无"); }else{ System.out.println(dis[i]); } //逆序打印路径方式,这次打印主要是为了看清楚path[]的作用,path[i]存储的是对应最短路径上的i的前驱结点 if (mark[i] != -1) {// 存在最短路径 System.out.print("v" + v + "到v" + i + "的最短路径为:"); int prePath = i; while (prePath != v) { System.out.print(prePath + "<-"); prePath = path[prePath]; } System.out.println(v); } //正序打印路径的方式 String pathStr = ""+i; String tmpStr = ""; if (mark[i] != -1) {// 存在最短路径 System.out.print("v" + v + "到v" + i + "的最短路径为:"); int prePath = i; while (prePath != v) { //System.out.print(prePath + "<-"); prePath = path[prePath]; tmpStr = prePath + "->"; pathStr = tmpStr + pathStr; } System.out.print(pathStr); } System.out.println("\n"); } } } public static void computeShortestPathOfEachPairNodes(){ int[][] A = {//测试 {0,4,11}, {6,0,2}, {3,Global.INF,0} }; int n = A[0].length; for(int i =0;i<n;i++){ dijkstraShortestPath(i,A); } } public static void main(String[] args) { //floydShortestPath(); int[][] A = {//测试 {INF,INF, 10, INF, 30,100 }, {INF,INF, 5, INF, INF,INF}, {INF,INF, INF,50, INF,INF}, {INF,INF, INF,INF, INF,10 }, {INF,INF, INF,20, INF,60 }, {INF,INF, INF,INF, INF,INF}, }; int v0 = 0;//求解v0到各节点的最短路径 dijkstraShortestPath(v0,A); //computeShortestPathOfEachPairNodes();//与Floyd做对比 } }
测试结果: