该问题,也是一个错误吧,发现也是在学习Floyd的动手实现过程中。我参考学习数据结构与算法书,自己也是动手敲了敲Floyd算法的代码,发现结果和正确的答案是不同的,就是说一些点是过不了的,是错误的。然后也是在网站上搜索Floyd算法,发现博主的和书上的没有什么不同,但测试出来就是不对。有bug就一定有原因,单步运行,一步一步找问题所在,最后在更新距离处发现了问题根源,不能单单只写 path[i][j] = k; 必须写完整,必须考虑 path[k][j] != j 这种情况。一些博主,很多数据结构书在此处只写了 path[i][j]=k; 这是错误的!大家可以去动手尝试一下,才能真正理解。越来越认可动手实现是最重要的也是最基本的!
完整Floyd代码及注释如下,多看看代码,尤其是if else:
最后附有该代码所对应的图,方便大家更好理解。
#include<iostream>
using namespace std;
typedef struct
{
char vexs[7]; //顶点值
int edges[7][7]; //邻接矩阵
int vnum, enum1; //顶点数和边数
}MGraph;
void CreateMGraph(MGraph*);
void floyd(MGraph* );
int main()
{
MGraph G;
CreateMGraph(&G);
floyd(&G);
}
void CreateMGraph(MGraph* G)
{
G->vnum = 7; G->enum1 = 7;
char c = 'A';
for (int i = 0; i < G->vnum; i++, c++)
G->vexs[i] = c;
for (int i = 0; i < G->vnum; i++)
for (int j = 0; j < G->vnum; j++)
G->edges[i][j] = 1000; //因为1000对于该程序已经足够大,认为无穷大
if (1)
{
G->edges[0][2] = 10; //也可以每次运行时再输入 不过麻烦
G->edges[1][2] = 7;
G->edges[1][6] = 9;
G->edges[1][3] = 5;
G->edges[2][0] = 10;
G->edges[2][1] = 7;
G->edges[3][1] = 5;
G->edges[3][5] = 2;
G->edges[4][5] = 6;
G->edges[5][4] = 6;
G->edges[5][3] = 2;
G->edges[5][6] = 3;
G->edges[6][1] = 9;
G->edges[6][5] = 3;
}
}
void floyd(MGraph* G)
{
int path[7][7], dist[7][7]; //path[i][j]是指i到j的路径中相对于j的前驱 dist[i][j]是i到j的最短路径距离
for (int i = 0; i < G->vnum; i++)
for (int j = 0; j < G->vnum; j++)
{
dist[i][j] = G->edges[i][j];
path[i][j] = j; //暂时默认path[i][j] j的前驱为j
}
for (int k = 0; k < G->vnum; k++) //注意三层for循环
for (int i = 0; i < G->vnum; i++)
for (int j = 0; j < G->vnum; j++)
if (dist[i][j] > (dist[i][k] + dist[k][j]))
{ //更新距离
dist[i][j] = dist[i][k] + dist[k][j];
if(path[k][j] != j) //if else是重点!!!读者细细体会
path[i][j] = path[k][j];
else
path[i][j] = k;
//很多博主,很多数据结构书在此处只写了 path[i][j]=k; 这是错误的!!!必须考虑 path[k][j] != j 这种情况
}
for (int i = 0; i < G->vnum; i++)
for (int j = 0; j < G->vnum; j++)
if (i != j) //直接忽略自身点到自身
{
printf("%c到%c的最短路径长度:%d\n", i + 17 + '0', j + 17 + '0', dist[i][j]);
printf("路径为:%c", i + 17 + '0');
if (path[i][j] == j)
printf("-->%c\n", j + 17 + '0');
else
{
int k = j, arry[7] = { 0 }, a = 0; //使用一个arry数组来逆序输出路径,保证路径的顺序正确
while (path[i][k] != k)
{
k = path[i][k];
arry[a] = k;
a++;
}
for (k = a - 1; k >= 0; k--) //注意逆序输出
printf("-->%c", arry[k] + 17 + '0');
printf("-->%c\n", j + 17 + '0');
}
}
}