本文受此文启发:最短路径问题—Dijkstra算法详解
实现内容:求出从某个顶点V0到其余顶点的最短路径的权值,以及具体路径
具体方法:
建立一个Dij结构,D存权值,Path存路径,visit保存此顶点是否被访问过
①根据邻接矩阵初始化D
②找出D中最小的顶点pos,并把visit[pos]设为1
③设置变量j从0增加到VexNum-1(遍历邻接矩阵第pos行),判断D[j]是否大于D[pos]+<pos,j>的权值(注意要设置判断条件 INT_MAX做加法会溢出成负数)
④如果大,那么就更新D[j]为D[pos]+<pos,j>的权值,同时更新D[j]的路径为D[pos]
⑤循环③④步,最多N-1次,注意,如果找不到最小的顶点需要跳出循环
测试图:
文本文档内容:
测试结果:
实现代码:
/*
实现内容:Dijkstra算法
VS2019 编译通过 王大花 2020.8.9
*/
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MaxVexNameLength 2
#define MaxPathLength 30
#define TextPath "C:\\Users\\86132\\Desktop\\第7章 作业\\最短路径\\ALGraph.txt"
char ch[MaxVexNameLength + 1];
//顶点结点
typedef struct _VexNode {
char Date[MaxVexNameLength + 1];
}VexNode;
typedef struct _DIJ {
char** Path;
int* D;
int* visit;
}DIJ;
//图
typedef struct _ALGraph {
VexNode* Vertics;
int VexNum, ArcNum;
int** ArcMatrix;
DIJ Dij;
}ALGraph;
//找到顶点位置
int Locate(char* ch) {
return (3 == strlen(ch)) ? 10 * (ch[1] - '0') + ch[2] - '0' : ch[1] - '0';
}
void Creat_ALGraph(ALGraph* G) {
FILE* fp = fopen(TextPath, "r");
fscanf(fp, "%d%d", &G->VexNum, &G->ArcNum);
//读取顶点信息 同时初始化邻接矩阵
G->Vertics = (VexNode*)malloc(sizeof(VexNode) * G->VexNum);
G->ArcMatrix = (int**)malloc(sizeof(int*) * G->VexNum);
for (int i = 0; i < G->VexNum; i++) {
fscanf(fp, "%s", G->Vertics[i].Date);
//初始化邻接矩阵
G->ArcMatrix[i] = (int*)malloc(sizeof(int) * G->VexNum);
for (int j = 0; j < G->VexNum; j++)
G->ArcMatrix[i][j] = INT_MAX;
}
//录入弧的信息
for (int i = 0; i < G->ArcNum; i++) {
char ch1[MaxVexNameLength + 1], ch2[MaxVexNameLength + 1];
int tmp;
fscanf(fp, "%s%s%d", ch1, ch2, &tmp);
G->ArcMatrix[Locate(ch1)][Locate(ch2)] = tmp;
}
//初始化Dij
G->Dij.D = (int*)malloc(sizeof(int) * G->VexNum);
G->Dij.Path = (char**)malloc(sizeof(char*) * G->VexNum);
G->Dij.visit = (int*)malloc(sizeof(int) * G->VexNum);
memset(G->Dij.visit, 0, sizeof(int) * G->VexNum);
for (int i = 0; i < G->VexNum; i++)
G->Dij.Path[i] = (char*)malloc(sizeof(char) * MaxPathLength);
fclose(fp);
}
void Shortest_Path_DIJ(ALGraph G) {
//获得初始顶点信息
printf("请输入开始点数据:");
scanf("%s", ch);
//初始化
for (int i = 0; i < G.VexNum; i++) {
G.Dij.D[i] = G.ArcMatrix[Locate(ch)][i];
strcpy(G.Dij.Path[i], ch);
}
G.Dij.D[Locate(ch)] = 0;
G.Dij.visit[Locate(ch)] = 1;
//最多剩N-1个顶点
for (int i = 1; i < G.VexNum; i++) {
//寻找距离最小顶点的位置
int tmp = INT_MAX, pos = Locate(ch);
for (int j = 0; j < G.VexNum; j++) {
if (!G.Dij.visit[j] && G.Dij.D[j] < tmp) {
tmp = G.Dij.D[j];
pos = j;
}
}
//如果V0没有出度了
if (pos == Locate(ch))
break;
G.Dij.visit[pos] = 1;
strcat(G.Dij.Path[pos], " -> ");
strcat(G.Dij.Path[pos], G.Vertics[pos].Date);
for (int j = 0; j < G.VexNum; j++) {
if (INT_MAX != G.ArcMatrix[pos][j] && INT_MAX != G.Dij.D[pos]) {
if (INT_MAX == G.Dij.D[pos] || G.Dij.D[j] > G.ArcMatrix[pos][j] + G.Dij.D[pos])
G.Dij.D[j] = G.Dij.D[pos] + G.ArcMatrix[pos][j];
G.Dij.Path[j][0] = '\0';
strcat(G.Dij.Path[j], G.Dij.Path[pos]);
}
}
}
}
void Print_Shortest_Path_DIJ(ALGraph G) {
printf("\n最短路径:\n\n\n");
for (int i = 0; i < G.VexNum; i++) {
if (Locate(ch) == i)
continue;
if (G.Dij.visit[i]) {
printf("路径:%-20s\t权重:%d\n", G.Dij.Path[i], G.Dij.D[i]);
}
else
printf("路径:%s -> %s \t\t\t不存在\n", ch, G.Vertics[i].Date);
}
}
int main() {
ALGraph G;
Creat_ALGraph(&G);
Shortest_Path_DIJ(G);
Print_Shortest_Path_DIJ(G);
return 0;
}