#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
/*
* 代码实现<<大话数据结构>>p267 图7-7-13,和dijkstra算法同一张图
* v0至v8分别用ABCDEFGHI代替
* 时间复杂度O(n)^3, 虽然比dijkstra O(n)^2慢,但是可以求得任意顶点间的最短路径及开销
*/
#define MAX 9
#define INFINITY 65535
typedef int NextPoint[MAX][MAX]; // 存放v到w的最短路径时要先经过的顶点,非parent关系
typedef int PathMatrix[MAX][MAX]; // 存放各顶点间的最短路径开销, D数组
// 图结构体
typedef struct {
char vexs[MAX]; // 顶点的数组,顶点类型为了简单使用char
int arc[MAX][MAX]; // 边表二维数组,值为权
int numVex;
}GRAPH, *PGRAPH;
void create(PGRAPH);
void gprint(GRAPH);
void addEdge(PGRAPH, int, int, int);
void floyd(GRAPH, PathMatrix *, NextPoint *);
void floyd(GRAPH graph, PathMatrix *D, NextPoint *P)
{
int v, w, k;
// 初始化D, P数组
for (v=0; v<graph.numVex; v++) {
for (w=0; w<graph.numVex; w++) {
(*D)[v][w] = graph.arc[v][w];
(*P)[v][w] = w;
}
}
/* 开始循环查找最短路径,更新D P数组
k为中转顶点,用于比对是否v经过k到w的开销比D数组中当前更小
如果更小,则说明k更有可能存在于v到w最短路径上,更新D,及P
*/
for (k=0; k<graph.numVex; k++) {
// v行
for (v=0; v<graph.numVex; v++) {
// v行所有w列
for (w=0; w<graph.numVex; w++) {
// 判断k是否有可能在v和w的最短路径上
if ((*D)[v][w] > (*D)[v][k] + (*D)[k][w]) {
// 更新两点间的距离和
(*D)[v][w] = (*D)[v][k] + (*D)[k][w];
//因为k存在于v到w的路径上,所以v想要到w需要先经过 v到k要经过的顶点
(*P)[v][w] = (*P)[v][k];
}
}
}
}
}
void addEdge(PGRAPH g, int i, int j, int v)
{
g->arc[i][j] = g->arc[j][i] = v;
}
void create(PGRAPH g)
{
int i, j;
g->numVex = 9;
// 创建顶点
g->vexs[0] = 'A';
g->vexs[1] = 'B';
g->vexs[2] = 'C';
g->vexs[3] = 'D';
g->vexs[4] = 'E';
g->vexs[5] = 'F';
g->vexs[6] = 'G';
g->vexs[7] = 'H';
g->vexs[8] = 'I';
// 初始化边表矩阵
for (i=0; i<g->numVex; i++) {
for (j=0; j<g->numVex; j++) {
g->arc[i][j] = INFINITY;
if (j == i)
g->arc[i][j] = 0; //行列相等时表示自身,标识为0
}
}
// 添加边及权值
// A v0, B v1, C v2, D v3, E v4, F v5, G v6, H v7, I, v8
addEdge(g, 0, 1, 1);
addEdge(g, 0, 2, 5);
addEdge(g, 1, 2, 3);
addEdge(g, 1, 4, 5);
addEdge(g, 1, 3, 7);
addEdge(g, 2, 4, 1);
addEdge(g, 2, 5, 7);
addEdge(g, 3, 4, 2);
addEdge(g, 3, 6, 3);
addEdge(g, 4, 5, 3);
addEdge(g, 4, 7, 9);
addEdge(g, 4, 6, 6);
addEdge(g, 5, 7, 5);
addEdge(g, 6, 7, 2);
addEdge(g, 6, 8, 7);
addEdge(g, 7, 8, 4);
}
void gprint(GRAPH graph)
{
int i, j;
for (i=0; i<graph.numVex; i++) {
for (j=0; j<graph.numVex; j++){
printf("%6d ", graph.arc[i][j]);
}
putchar('\n');
}
}
int main(void)
{
int i, j, k;
GRAPH graph;
NextPoint next_point;
PathMatrix distance;
create(&graph);
gprint(graph);
floyd(graph, &distance, &next_point);
printf("D数组(任意顶点间的最短路径开销或者叫距离)\n");
for (i=0; i<MAX; i++) {
for (j=0; j<MAX; j++) {
printf("%6d ", distance[i][j]);
}
putchar('\n');
}
printf("任意顶点间的最短路径:\n");
for (i=0; i<MAX; i++) {
for (j=i+1; j<MAX; j++) {
printf("%d -> %d distance: %3d, path:", i, j, distance[i][j]);
printf("%d->", i); // 先打印源点
k = next_point[i][j];
while (k != j) {
printf("%d->", k);
k = next_point[k][j]; // 相当于递归查找
}
printf("%d\n", k);
}
}
return 0;
}
output
# gcc shortestPath_floyd.c && ./a.out
0 1 5 65535 65535 65535 65535 65535 65535
1 0 3 7 5 65535 65535 65535 65535
5 3 0 65535 1 7 65535 65535 65535
65535 7 65535 0 2 65535 3 65535 65535
65535 5 1 2 0 3 6 9 65535
65535 65535 7 65535 3 0 65535 5 65535
65535 65535 65535 3 6 65535 0 2 7
65535 65535 65535 65535 9 5 2 0 4
65535 65535 65535 65535 65535 65535 7 4 0
D数组(任意顶点间的最短路径开销或者叫距离)
0 1 4 7 5 8 10 12 16
1 0 3 6 4 7 9 11 15
4 3 0 3 1 4 6 8 12
7 6 3 0 2 5 3 5 9
5 4 1 2 0 3 5 7 11
8 7 4 5 3 0 7 5 9
10 9 6 3 5 7 0 2 6
12 11 8 5 7 5 2 0 4
16 15 12 9 11 9 6 4 0
任意顶点间的最短路径:
0 -> 1 distance: 1, path:0->1
0 -> 2 distance: 4, path:0->1->2
0 -> 3 distance: 7, path:0->1->2->4->3
0 -> 4 distance: 5, path:0->1->2->4
0 -> 5 distance: 8, path:0->1->2->4->5
0 -> 6 distance: 10, path:0->1->2->4->3->6
0 -> 7 distance: 12, path:0->1->2->4->3->6->7
0 -> 8 distance: 16, path:0->1->2->4->3->6->7->8
1 -> 2 distance: 3, path:1->2
1 -> 3 distance: 6, path:1->2->4->3
1 -> 4 distance: 4, path:1->2->4
1 -> 5 distance: 7, path:1->2->4->5
1 -> 6 distance: 9, path:1->2->4->3->6
1 -> 7 distance: 11, path:1->2->4->3->6->7
1 -> 8 distance: 15, path:1->2->4->3->6->7->8
2 -> 3 distance: 3, path:2->4->3
2 -> 4 distance: 1, path:2->4
2 -> 5 distance: 4, path:2->4->5
2 -> 6 distance: 6, path:2->4->3->6
2 -> 7 distance: 8, path:2->4->3->6->7
2 -> 8 distance: 12, path:2->4->3->6->7->8
3 -> 4 distance: 2, path:3->4
3 -> 5 distance: 5, path:3->4->5
3 -> 6 distance: 3, path:3->6
3 -> 7 distance: 5, path:3->6->7
3 -> 8 distance: 9, path:3->6->7->8
4 -> 5 distance: 3, path:4->5
4 -> 6 distance: 5, path:4->3->6
4 -> 7 distance: 7, path:4->3->6->7
4 -> 8 distance: 11, path:4->3->6->7->8
5 -> 6 distance: 7, path:5->7->6
5 -> 7 distance: 5, path:5->7
5 -> 8 distance: 9, path:5->7->8
6 -> 7 distance: 2, path:6->7
6 -> 8 distance: 6, path:6->7->8
7 -> 8 distance: 4, path:7->8