最短路径——迪杰斯特拉(Dijkstra)弗洛伊德(Floyd)
一、迪杰斯特拉算法(Dijkstra)
1. 问题:
求从每个源点到其余各顶点的最短路径。
2.存储结构:
1)图的存储结构: 带权的邻接矩阵
2)辅助数组:
一维数组dist:dist[ i ]表示当前求出的从源点到顶点 i 的路径长度,其初始状态为邻接矩阵第 i 行的值;
二维数组path:二维数组第 i 行path[ i ]表示源点到 i 的路径中经过的顶点下标集合,其初始值为 -1 。
3)算法实现:
void dijkstra(MGraph G, int v) {
int dist[MAXSIZE]; //dist[i]:源点到点 i 的路径长度
int path[MAXSIZE][MAXSIZE]; //path[i][]:源点到点 i 经过的顶点j下标集合
int i, j, k, m, min, n, flag;
for(i=0; i<G.vexNum; i++) { //path[][]初始化为-1
for(j=0; j<G.vexNum; j++) {
path[i][j] = -1;
}
}
for(i=0; i<G.vexNum; i++) {
dist[i]=G.arcs[v][i]; //dist[]初始状态为arcs[][]第v行
if(dist[i]!=0 && dist[i]!=INFINITY) {//与源点 v 有关系的顶点第一个经过的点为 v
path[i][0]=v;
}
}
n=0; //打印最短路径时对应第%d条
flag=1; //循环结束标志
//从小到大找最短路径
while(flag) {
k=0; //每一轮循环中要选择的最短路径长度对应的顶点下标
min=INFINITY; //每一轮循环中要选择的最短路径长度
for(j=0; j<G.vexNum; j++) { //找dist最小值
if(dist[j]!=0 && dist[j]<min) {
k=j;
min=dist[j];
}
}
printf("第%d条最短路径长度为%d--(", ++n, min); //显示最短路径
for(j=0; j<G.vexNum; j++) {
if(path[k][j]!=-1) { //打印从源点到最短路径顶点经过的顶点
printf("%d,", path[k][j]);
}
}
printf("%d)\n", k);
for(j=0; j<G.vexNum; j++) { //更新dist和path
if(j!=k && G.arcs[k][j]!=INFINITY) {
if(dist[k]+G.arcs[k][j]<dist[j]) { //用更短的路径长度替换原来的dist
dist[j]=dist[k]+G.arcs[k][j];
for(m=0; m<G.vexNum; m++) { //将path[k]复制到path[j]中
path[j][m]=path[k][m];
}
m=0;
while(m<G.vexNum && path[j][m]!=-1) {//找path[j]中最后一个数据的下标,即第1个-1的下标
m++;
}
path[j][m]=k; //将下标j加到path[j]的尾部
}//if
}//if
}//for
dist[k]=0; //标志该顶点已输出
flag=0; //判断路径是否求完,若flag=1继续求,否则结束
for(j=0; j<G.vexNum; j++) {
if(dist[j]!=0 && dist[j]<INFINITY) {
flag = 1;
}
}//for
}//while
for(i=0; i<G.vexNum; i++) {
if(dist[i]==INFINITY) {
printf("由%d作为源点%d顶点无法到达\n", v, i);
}
}
}
二、弗洛伊德算法(Floyd)
1. 问题:
求每一对顶点间的最短路径
2.存储结构:
1)图的存储结构: 带权的邻接矩阵
2)辅助数组:
二维数组d:d[ i ][ j ]表示当前求出的从 i 到 j 的路径长度;
二维数组path:每个二维数组元素path[ i ][ j ]是一个一维整形数组,存放当前 i 到 j 的路径做经过的顶点下标集合。
3)算法实现:
void floyd(MGraph G) {
int i, j, k, m, n, p;
int d[MAXSIZE][MAXSIZE];
PATHINT path[MAXSIZE][MAXSIZE];
for (i=0; i<G.vexNum; i++) { //初始化数组 d 和 path
for(j=0; j<G.vexNum; j++) {
d[i][j] = G.arcs[i][j];
for (k=0; k<MAXSIZE; k++) {
path[i][j][k] = -1;
}
}
}//for
printf("\ndist的初值\n");
for (i=0; i<G.vexNum; i++) {
for (j=0; j<G.vexNum; j++) {
printf("%6d", d[i][j]);
printf("\t");
}
printf("\n");
}
for (i=0; i<G.vexNum; i++) { //存放初始路径
for (j=0; j<G.vexNum; j++) {
if (d[i][j]!=INFINITY && d[i][j]!=0) {
path[i][j][0] = i;
path[i][j][1] = j;
}
}//for-j
}//for-i
printf("\npath的初值\n");
for (i=0; i<G.vexNum; i++) {
for (j=0; j<G.vexNum; j++) {
for (k=0; path[i][j][k]!=-1; k++) {
printf("%d,", path[i][j][k]);
}//for-k
printf("\t");
}//for-j
putchar('\n');
}//for-i
for (k=0; k<G.vexNum; k++) { //用经过点 k 的路径更新上一次的路径
for (i=0; i<G.vexNum; i++) {
if (i==k) {
continue;
}
for (j=0; j<G.vexNum; j++) {
if (j==k) {
continue;
}
if (d[i][k]+d[k][j] < d[i][j]) {// d(k)[i][j] = min{ d(-1)[i][j], d(-1)[i][k] + d(-1)[k][j]) }
d[i][j] = d[i][k] + d[k][j];
//m,n两个for循环均为将经过k的更短的路径复制的过程
for (m=0; m<G.vexNum && path[i][k][m]!=-1; m++) {
path[i][j][m] = path[i][k][m];
}//for-m
for (n=0; n<G.vexNum && path[k][j][n]!=-1; n++) {
if (n>1) {
m++;
}
path[i][j][m] = path[k][j][n];
}//for-n
}//if
}//for-j
}//for-i
printf("\ndist的第%d次迭代结果\n", k+1);
for(m=0; m<G.vexNum; m++) {
for (n=0; n<G.vexNum; n++) {
printf("%6d", d[m][n]);
}//for-n
putchar('\n');
}//for-m
printf("\npath的第%d次迭代结果\n", k+1);
for (i=0; i<G.vexNum; i++) {
for (j=0; j<G.vexNum; j++) {
for (p=0;path[i][j][p]!=-1; p++) {
printf("%d,", path[i][j][p]);
}//for-p
printf("\t");
}//for-j
putchar('\n');
}//for-i
}//for-k
}//floyd