算法背景:
图中的A,B,C,D,E,F,G,代表7个村庄,边上的权值带表两村庄之间的距离,现在要从某一个村庄,例如G村庄,往另外几个村庄送邮件,问G村庄到其他各村庄的最短距离分别是多少?
思路:
该问题实际是求从某一顶点到其余顶点的最短距离,即单源点到其余顶点的距离。可以用迪杰斯特拉算法求解。
dijkstra算法求最短距离
算法思路:
该算法使用了三个辅助数组,首先应理解它们的含义:
- visited[]:保存各顶点是否被访问过,初始时,除了其实顶点为true外,其余都是false。
- distance[]:存放动态的单源点到其余点的最短距离,初始时为单源点到各店的距离,其中单源点自身距离设置为0。
- prePath[]:保存当前结点的前驱结点,方便最后找最短距离的路径,初始时除与单源点有直接路径的顶点设置为单源点索引外其余都设置为-1,即没有前驱点。
该算法将图中顶点分为两类:已访问过的和没访问过的,这里的已访问过是指对应顶点的distance中的距离已经是真实的最短的距离了,通过visited中的true和false实现。初始时,只有起始顶点为true,然后在false的顶点中找出动态距离最短的顶点(体现贪心思想),将其置为true,此时访问该点的邻接边,并对比“过渡距离”是否小于distance中的距离,小于则更新distance和prePath。依次循环直到都置为true为止。
核心代码:
算法分析:
该算法用了两层for,外层为需要访问的顶点个数,时间复杂度为O(n),内层有两个for,第一个for为挑选未被访问的顶点的最短距离,时间复杂度为O(n),第二个for为在与选中顶点有直接路径的顶点中对比距离是否需要更新,时间复杂度为O(n),所以总的时间复杂度为O(n²)。
dijkstra算法可通过改变存储结构(邻接表)和存储距离(优先队列)的方式做优化,使最后复杂度为O(nlogn)。
具体见:迪杰斯特拉算法优化(dijkstra)https://blog.csdn.net/weixin_48898946/article/details/121004513
public void dijkstra(int index) {for(int i = 0; i < numOfVertex;i++) {//初始化各辅助数组distant[i] = edge[index][i];if(edge[index][i] != INF) {prePath[i] = index;}else {prePath[i] = -1;}}visit[index] = true;//置初始起点已访问for(int i = 0; i < numOfVertex - 1;i++) {int des = 0;int minDis = INF;for(int j = 0; j < numOfVertex ;j++) {//挑选为被访问的最短距离的顶点if(visit[j] == false && minDis > distant[j]) {minDis = distant[j];des = j;}}visit[des] = true;//更新为已访问for(int j = 0; j < numOfVertex;j++) {//对比更新最短距离int len = edge[des][j] + distant[des];if(len < distant[j] && len < INF) {distant[j] = len;prePath[j] = des;}}}System.out.printf("顶点%c到其余各点的最短距离:\n",vertex[index]);for (int i = 0; i < numOfVertex; i++) {if (i != index) {System.out.printf("顶点%c到顶点%c的最短距离是%d\n", vertex[index], vertex[i], distant[i]);}}System.out.println();
}
java代码:
import java.util.*;public class Dijkstra {public static void main(String[] args) {final int INF = 0x3f3f3f3f;char[]vertex = {'A','B','C','D','E','F','G'};int [][]edge = new int [][] {{INF,5,7,INF,INF,INF,2},{5,INF,INF,9,INF,INF,3},{7,INF,INF,INF,8,INF,INF},{INF,9,INF,INF,INF,4,INF},{INF,INF,8,INF,INF,5,4},{INF,INF,INF,4,5,INF,6},{2,3,INF,INF,4,6,INF}};Graph graph = new Graph(vertex, edge);graph.printGraph();System.out.println("\n初始起点为G点:\n");graph.dijkstra(6);graph.printPath(6);}
}
class Graph{final int INF = 0x3f3f3f3f;//设置一个“大数”char []vertex;//顶点数组int [][]edge;//邻接矩阵int numOfVertex;//顶点个数boolean []visit;//访问标志数组int []distant;//最短距离数组int []prePath;//最短路径前驱数组public Graph(char[] vertex, int[][] edge) {this.vertex = vertex;this.edge = edge;numOfVertex = vertex.length;visit = new boolean[numOfVertex];distant = new int [numOfVertex];prePath = new int [numOfVertex];}public void printGraph() {System.out.println("邻接矩阵为:");for(int[] data : edge) {System.out.println(Arrays.toString(data));}}public void dijkstra(int index) {for(int i = 0; i < numOfVertex;i++) {//初始化各辅助数组distant[i] = edge[index][i];if(edge[index][i] != INF) {prePath[i] = index;}else {prePath[i] = -1;}}visit[index] = true;//置初始起点已访问for(int i = 0; i < numOfVertex - 1;i++) {int des = 0;int minDis = INF;for(int j = 0; j < numOfVertex ;j++) {//挑选为被访问的最短距离的顶点if(visit[j] == false && minDis > distant[j]) {minDis = distant[j];des = j;}}visit[des] = true;//更新为已访问for(int j = 0; j < numOfVertex;j++) {//对比更新最短距离int len = edge[des][j] + distant[des];if(len < distant[j] && len < INF) {distant[j] = len;prePath[j] = des;}}}System.out.printf("顶点%c到其余各点的最短距离:\n",vertex[index]);for (int i = 0; i < numOfVertex; i++) {if (i != index) {System.out.printf("顶点%c到顶点%c的最短距离是%d\n", vertex[index], vertex[i], distant[i]);}}System.out.println();}public void printPath(int m) {for(int i = 0; i < numOfVertex;i++) {if(i == m) continue;int []flag = new int[numOfVertex];int index = 0;flag[index++] = i;int k = i;while(true) {k = prePath[k];if(k == m || k == -1)break;flag[index++] = k;}flag[index] = m;System.out.printf("顶点%c到顶点%c的最短路径为:",vertex[m],vertex[i]);for(int j = index; j >= 0; j--) {System.out.print(vertex[flag[j]] + " ");}System.out.println();}}
}
程序输出:
邻接矩阵为:
[1061109567, 5, 7, 1061109567, 1061109567, 1061109567, 2]
[5, 1061109567, 1061109567, 9, 1061109567, 1061109567, 3]
[7, 1061109567, 1061109567, 1061109567, 8, 1061109567, 1061109567]
[1061109567, 9, 1061109567, 1061109567, 1061109567, 4, 1061109567]
[1061109567, 1061109567, 8, 1061109567, 1061109567, 5, 4]
[1061109567, 1061109567, 1061109567, 4, 5, 1061109567, 6]
[2, 3, 1061109567, 1061109567, 4, 6, 1061109567]初始起点为G点:顶点G到其余各点的最短距离:
顶点G到顶点A的最短距离是2
顶点G到顶点B的最短距离是3
顶点G到顶点C的最短距离是9
顶点G到顶点D的最短距离是10
顶点G到顶点E的最短距离是4
顶点G到顶点F的最短距离是6顶点G到顶点A的最短路径为:G A
顶点G到顶点B的最短路径为:G B
顶点G到顶点C的最短路径为:G A C
顶点G到顶点D的最短路径为:G F D
顶点G到顶点E的最短路径为:G E
顶点G到顶点F的最短路径为:G F