迪杰斯特拉算法(DiJkstra)
如果要从V0到V8,只需要找出V0所在的边的最短路径,然后在再另一个顶点中找出最短的路径,以此类推一直到目标点。
#define INFINITY 65535
#define max 100
//typedef struct //测试样例
//{
// char vex[max] = { 'a','b','c','d','e','f','g','h','i' };
// int link[9][9] = { 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}; // 测试样例
// int vexnum = 9, edgnum = 15;
//}MGraph;
typedef struct
{
char vex[max];
int link[max][max];
int vexnum, edgnum;
}MGraph; // 创建图
void MGraph_init(MGraph *G) // 初始化图
{
printf("请输入顶点数和边数");
scanf_s("%d %d", &G->vexnum, &G->edgnum);
for (int i = 0; i < G->vexnum; i++) // 初始化顶点信息
{
printf("请输入顶点信息");
scanf_s(" %c", &G->vex[i]);
}
for (int i = 0; i < G->vexnum; i++) //初始化指向 0表示指向自己,INFINITY表示不指向
{
for (int j = 0; j < G->vexnum; j++)
{
G->link[i][j] = INFINITY; // 默认为不指向
}
G->link[i][i] = 0;
}
int i, j, w;
for (int k = 0; k < G->edgnum; k++) // 初始化各各顶点的指向
{
printf("输入(vi,vj)的下标i,j和指向w \n");
scanf_s("%d %d %d", &i, &j, &w);
G->link[i][j] = w;
G->link[j][i] = G->link[i][j]; // 因为在矩阵中,他们是对称的
}
for (int y = 0; y < G->vexnum; y++) //打印二维数组
{
for (int u = 0; u < G->vexnum; u++)
{
printf("%d ", G->link[y][u]);
}
printf("\n");
}
}
// v0表示从v0点开始,到其他点的最短距离,vexsub储存从v0到v最短路径的最短路路径所连接的顶点,shorttable储存的是从v点到其他点最短权值
void Shortest_Dijkstra(MGraph G, int v0, int vexsub[max], int shorttable[max])
{
int min, w, k,v;
int final[max]; // 记录访问过的下标,每次访问过后下标置1
for(int i = 0;i<G.vexnum;i++) // 初始化数据
{
final[i] = 0;
shorttable[i] = G.link[v0][i];
vexsub[i] = 0;
}
shorttable[v0] = 0; // v到v忽略不计
final[v0] = 1; // 不访问自身
for (v = 1; v < G.edgnum; v++) // 开始循环,寻找最短路径
{
min = INFINITY;
for (w = 0; w < G.edgnum; w++) // 寻找最小值
{
if (!final[w] && shorttable[w] < min)
{
min = shorttable[w];
k = w;
}
}
final[k] = 1; // 将访问过的最小值下标置为1
//重置最小值,在所有经过最小值下标的路径的权值加上最小值与最小值顶点到另外顶点的最小值比较
for (w = 0; w < G.vexnum; w++)
{
if (!final[w] && (min + G.link[k][w]) < shorttable[w])
{
shorttable[w] = min + G.link[k][w];
vexsub[w] = k; // 记录最小值顶点所指向的下标
}
}
}
}
int main()
{
MGraph G;
int vexsub[max], shorttable[max];
//MGraph_init(&G);
Shortest_Dijkstra(G, 6, vexsub, shorttable);
for (int u = 0; u < G.vexnum; u++)
{
printf("vexsub = %d,shorttable = %d \n", vexsub[u], shorttable[u]);
}
}
v0表示从v0点开始,到其他点的最短距离,vexsub储存从v0到v最短路径的最短路路径所连接的顶点,shorttable储存的是从v点到其他点最短权值,final数组用来记录访问过的顶点,避免重复访问。
初始化的时候,vexsub初始化为0,shorttable记录V0顶点到其他顶点的最短路程,final全部初始化为0,表示现在所有的顶点都还没有访问。之后将final[v0] = 1;表示开始访问该顶点,shorttable[v0] = 0,表示不从v0点到v0点。
测试样例图:
开始时,将min置于最大值,找出V0顶点到领边顶点的最小值,并且将最小下标赋值给k,最小值赋值给min,之后在将访问过的下标置1,之后开始进一步的比较,让min加上其他边的权值与shorttable中的值比较。如果更加的小就写进shorttable中,并且将下标写进vexsub。
比如:v0 - v2在shorttable中权值是5,但是v0的最短路径是v1,所以min = 1 ,这个时候进一步循环,发现,min+G[k][w] <shorttable,所以v0到V2的最短距离不再是5,而是4。以此类推,第二次循环的时候开始循环 v1。直到循环解释