图中的A,B,C,D,E,F,G,代表7个村庄,边上的权值带表两村庄之间的距离,现在要从某一个村庄,例如G村庄,往另外几个村庄送邮件,问G村庄到其他各村庄的最短距离分别是多少?
该问题实际是求从某一顶点到其余顶点的最短距离,即单源点到其余顶点的距离。可以用迪杰斯特拉算法求解。
该算法使用了三个辅助数组,首先应理解它们的含义:
该算法将图中顶点分为两类:已访问过的和没访问过的,这里的已访问过是指对应顶点的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();
}
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