东北大学大作业-活力长者社区-班车路线管理(创新)
开发语言:c语言
编译工具:vscode
引用的小伙伴麻烦点下关注,有任何疑问欢迎大家留言哎
1.运行效果
2.迪杰斯特拉算法实现思路
为了求得两站点间的最短路径,需要建立3个数组分别是final[M],dist[M], path[M](代码中命名有所不同)。final负责标记各顶点是否已经找到最短路径,dist负责记录目前能够找到的最短的最优的一条路径。path负责记录最短最优路径的前驱。如下图所示。
之后,需要对三个数组分别进行初始化,初始化完成后正式开始执行算法,首先循环遍历所有结点,找到没有确定最短路径且dist值最小的顶点,将其final值设为TRUE。然后需要检查其邻节点,若final为FALSE且本轮dist值最小的顶点dist值加上该顶点到邻节点距离小于邻节点的dist值时,需要更新dist和path信息。之后继续循环遍历所有节点,执行之上操作,直至终点的final值为TRUE为止。终点的dist值即为最短路径长度,通过path数组也可以找点具体的最短路径。
3.完整代码
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<string.h>
#include<windows.h>
#include <malloc.h>
#define BUFF 1024
# define TRUE 1
# define FALSE 0
# define OK 1
# define ERROR 0
# define OVERFLOW -2
# define M 100 //定义车站最大数量
//定义路径
typedef struct Route{
int iPF; //边上节点i
int jPF; //边上节点j
double len;//路径长度
struct Route *iLink; //依附于节点i的下一节点
struct Route *jLink; //依附于节点j的下一节点
}Route, *RT;
//定义车站
typedef struct PlatNode{
char name[10];//车站名称
Route *first; //第一条路径
}PlatNode, PlatForm[M];
//定义路线图
typedef struct RtGNode{
PlatForm platList;
int plnum, rtnum;//车站数量,路径数量
}RtGNode, *RtGraph;
//**************************************班车路线管理函数定义**************************************************
//班车路线管理控制函数
void sRouteControl();
//班车路线管理页面函数
void sRoutePage();
void sRouteChoosePage(RtGraph G);
void addRtNodePage(RtGraph G);
void minRoutePage(RtGraph G);
//班车路线管理文件处理函数
int readRtGraph(RtGraph G);
int writeRtGraph(RtGraph G);
//班车路线管理操作函数
int addRTNode(RtGraph G,char *name);
void printfPlatForm(RtGraph G);
int findPlatForm(RtGraph G, char* pName);
void clearRTFile();
//迪杰斯特拉算法函数定义
void dijkstra(RtGraph G, int begin, int end);
//定义顶点
int main()
{
sRouteControl();
return 0;
}
//********************
//**************************************班车路线管理函数实现***************************************************
//********************
//**************************************班车路线管理页面函数实现***********************************************
void sRouteControl(){
sRoutePage();
RtGraph G = (RtGraph)malloc(sizeof(RtGNode));
readRtGraph(G);
printf(" 按任意键开始");
getchar();
system("cls");
sRouteChoosePage(G);
free(G);
}
void sRoutePage(){
system("cls");
color(2);
printf(" **********************************\n");
color(7);
printf(" **********************************\n");
color(6);
printf(" ******欢迎来到班车路线管理!******\n");
color(7);
printf(" **********************************\n");
color(2);
printf(" **********************************\n");
color(7);
}
void sRouteChoosePage(RtGraph G){
while(1){
system("cls");
int num;
printf("\n===============================\n");
color(6);
printf("1.新增班车路线\n2.求站点间最短路径\n3.清空班车路线图\n4.保存并退出系统\n");
color(7);
printf("\n===============================\n\n");
printf("请输入您所选的数字:");
scanf("%d",&num);
switch (num){
case 1:
addRtNodePage(G);
writeRtGraph(G);
break;
case 2:
minRoutePage(G);
break;
case 3:
clearRTFile();
break;
case 4:
return;
default:
printf("错误!");
printf(" 你所输入数字不存在:");
break;
}
}
}
//新增班车站点页面
void addRtNodePage(RtGraph G){
char name[10];
int j;
while(1){
system("cls");
color(7);
printf("\n=======================================\n");
color(6);
printf("请按指示录入新建班车路线信息\n");
color(7);
printf("=======================================\n\n");
printf("现已有站点如下所示:\n");
printfPlatForm(G);
color(7);
printf("\n=========================================\n");
color(6);
printf("请输入新建班车路线站点名称(小于等于10个字符):");
scanf("%s",&name);
if(addRTNode(G, name)){
printf("\n接下来请为班车站点%s建立班车路线", G->platList[G->plnum-1].name);
addRoutePage(G, G->plnum - 1);
}
printf("\n请选择下一步操作 按1表示返回班车路线管理主页面,否则继续新建:\n");
scanf("%d",&j);
if(j == 1){
return;
}
}
}
//新增班车路线页面
void addRoutePage(RtGraph G, int RF){
color(7);
printf("\n=========================================\n");
color(6);
char name[10];
double len;
int j;
while(1){
printf("\n请输入另一端班车路线站点名称(小于等于10个字符):");
scanf("%s", &name);
int RS = findPlatForm(G, name);
if(RS == -1){
printf("输入节点不存在,请重新输入\n");
}else{
printf("请输入班车路线长度:");
scanf("%lf", &len);
addRoute(G, RF, RS, len);
}
printf("\n请选择下一步操作 按1表示结束新建班车路线,否则继续新建:\n");
scanf("%d",&j);
if(j == 1){
return;
}
}
}
//最短路径页面
void minRoutePage(RtGraph G){
char begin[10];
char end[10];
int begin_num;
int end_num;
int j;
while(1){
system("cls");
color(7);
printf("\n=======================================\n");
color(6);
printf("现使用迪杰斯特拉算法求最短路径\n");
color(7);
printf("=======================================\n\n");
printf("现已有站点如下所示:\n");
printfPlatForm(G);
color(7);
printf("\n=========================================\n");
color(6);
printf("请输入班车出发站点名称(小于等于10个字符):");
scanf("%s",&begin);
begin_num = findPlatForm(G, begin);
printf("\n请输入班车到达站点名称(小于等于10个字符):");
scanf("%s", &end);
end_num = findPlatForm(G, end);
if(begin_num == -1 || end_num == -1){
printf("班车站点不存在\n");
}else{
dijkstra(G, end_num, begin_num);
}
printf("\n请选择下一步操作 按1表示返回班车路线管理主页面,否则继续:\n");
scanf("%d",&j);
if(j == 1){
return;
}
}
}
//********************
//**************************************页面颜色设计函数实现**********************************************
//********************
void color(int x){
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),x);
}
//**************************************班车路线管理文件处理函数实现*******************************************
//从文件中读取路径
int readRtGraph(RtGraph G){
G->plnum = 0;
G->rtnum = 0;
printf("开始读取文件");
char line[BUFF] = {0};//打开文件流
FILE* file;
file = fopen("D:\\RtGraph.txt","r");
if(file){
while (fgets(line, BUFF, file) != NULL) {
strtok(line, "\n");//截取有效字符串
printf("截取的有效字符串为:%s\n", line);
if(!line){
break;
}
//***
//*
//**下面开始构建站点
//*
//***
char* str1 = strtok(line, "-");//截取站点1名称
printf("读取站点1名称为:%s\n", str1);
int pF = findPlatForm(G, str1);
//如果站点不存在,则构建新的站点
if(pF == -1){
strcpy(G->platList[G->plnum].name, str1);
printf("新增站点名称为:%s\n", G->platList[G->plnum].name);
G->platList[G->plnum].first = NULL;
pF = G->plnum;
G->plnum++;
}
char* str2 = strtok(NULL, "-");//截取站点2名称
printf("读取站点2名称为:%s\n", str2);
int pS = findPlatForm(G, str2);
//如果站点不存在,则构建新的站点
if(pS == -1){
strcpy(G->platList[G->plnum].name, str2);
printf("新增站点名称为:%s\n", G->platList[G->plnum].name);
G->platList[G->plnum].first = NULL;
pS = G->plnum;
G->plnum++;
}
//***
//*
//**下面开始构建边
//*
//***
char *lenStr = strtok(NULL, "-");//截取路线距离
//头插法
//首先申请给内存动态分配空间
RT rt = (RT)malloc(sizeof(Route));
G->rtnum++;
rt->len = atof(lenStr);
rt->iPF = pF;
rt->jPF = pS;
rt->iLink = NULL;
rt->jLink = NULL;
rt->iLink = G->platList[pF].first;
rt->jLink = G->platList[pS].first;
G->platList[pF].first = rt;
G->platList[pS].first = rt;
}
}else{
// printf("文件打开失败\n");
return ERROR;
}
fclose(file);//关闭文件流
return OK;
}
int writeRtGraph(RtGraph G){
//是否访问过边
int visit[G->rtnum][G->rtnum];
for(int i = 0; i < G->rtnum; i++){
for(int j = 0; j < G->rtnum; j++){
visit[i][j] = FALSE;
}
}
FILE* file = fopen("D:\\RtGraph.txt", "w+");//文件
printf("向文件中存入数据如下所示:\n");
for(int z = 0; z < G->plnum; z++){
//遍历站点连接的边
RT R = G->platList[z].first;
while(R){
if(!visit[R->iPF][R->jPF]){
printf("%s-%s-%lf\n", G->platList[R->iPF].name, G->platList[R->jPF].name, R->len);
fprintf(file, "%s-%s-%lf\n", G->platList[R->iPF].name, G->platList[R->jPF].name, R->len);
visit[R->iPF][R->jPF] = TRUE;
}
// printf("\n读取一个子节点\n");
if(z == R->iPF){
R = R->iLink;
}else if(z == R->jPF){
R = R->jLink;
}
}
}
fclose(file);//关闭文件流
return OK;
}
//**************************************班车路线管理操作函数实现********************************************
//新增站点
int addRTNode(RtGraph G,char *name){
if(G->plnum == M){
printf("班车路线站点已满,无法新建\n");
return ERROR;
}
if(findPlatForm(G, name) != -1){
printf("改路线结点已存在\n");
return ERROR;
}
strcpy(G->platList[G->plnum].name, name);
G->platList[G->plnum].first = NULL;
G->plnum ++;
printf("班车路线节点%s已经建立\n", G->platList[G->plnum-1]);
return OK;
}
//新增路线
int addRoute(RtGraph G, int pF, int pS, double Rlen){
if(pF == -1 || pS == -1){
printf("路线两边站点不存在年\n");
return ERROR;
}
//首先申请给内存动态分配空间
RT rt = (RT)malloc(sizeof(Route));
G->rtnum++;
rt->len = Rlen;
rt->iPF = pF;
rt->jPF = pS;
rt->iLink = NULL;
rt->jLink = NULL;
rt->iLink = G->platList[pF].first;
rt->jLink = G->platList[pS].first;
G->platList[pF].first = rt;
G->platList[pS].first = rt;
printf("路线构建完成\n");
return OK;
}
void printfPlatForm(RtGraph G){
printf("\n");
for(int i = 0; i < G->plnum; i++){
color(2);
printf("%s\n", G->platList[i].name);
}
}
//发现站点
int findPlatForm(RtGraph G, char* pName){
for(int i = 0; i < G->plnum; i++){
//如果发现
if(!strcmp(G->platList[i].name, pName)){
return i;
}
}
//如果没有发现
return -1;
}
//清空文件
void clearRTFile(){
FILE *file;
file = fopen("D:\\RtGraph.txt", "w+");
fclose(file);
printf("清空文件成功\n");
}
//**************************************迪杰斯特拉算法函数实现********************************************
//迪杰斯特拉算法求最短路径
void dijkstra(RtGraph G, int begin, int end){
int finalRt[G->plnum];//标记各顶点是否找到最短路径
double distRt[G->plnum];//最短路径长度
int pathRt[G->plnum];//路径上的前驱
int min;
color(7);
color(2);
printf("\n现在开始运行迪杰斯特拉算法\n");
printf("\n===============================\n");
//****************
//**算法首先要进行初始化操作
//****************
printf("\n算法首先要进行初始化操作\n");
int i = 0;
//首先对finalRt数组进行初始化
for(i = 0; i < G->plnum; i++){
finalRt[i] = FALSE;
}
finalRt[begin] = TRUE;
//对最短路径长度进行初始化
for(int j = 0; j < G->plnum; j++){
distRt[j] = -1; //使用-1表示无穷
}
distRt[begin] = 0;
printf("%s已经确定最短路径为:%d\n", G->platList[begin], distRt[begin]);
//对路径前驱进行初始化
for(int z = 0; z < G->plnum; z++){
pathRt[z] = -1; //-1表示暂无前驱节点
}
RT R = G->platList[begin].first;
while(R){
if(begin == R->iPF){
distRt[R->jPF] = R->len;
pathRt[R->jPF] = R->iPF;
R = R->iLink;
}else if(begin == R->jPF){
distRt[R->iPF] = R->len;
pathRt[R->iPF] = R->jPF;
R = R->jLink;
}
}
//****************
//**算法正式开始执行
//****************
printf("\n算法正式开始执行\n");
while(!finalRt[end]){
//首先循环遍历所有结点,找到没有确定最短路径且,distRt值最小的顶点
min = -1; //distRt最小的结点
for(i = 0; i < G->plnum; i++){
if(!finalRt[i]){
if(distRt[i] != -1 && min == -1){//如果最小顶点没被确定
min = i;
}else if(distRt[i] != -1 && distRt[i] < distRt[min]){//确定了但有更小的(不为无穷)
min = i;
}
}
}
//找到distRt值最小的顶点后,将finalRt设为TRUE
finalRt[min] = TRUE;
printf("已经确定最短路径%s至%s为:%lf\n", G->platList[pathRt[min]], G->platList[min], distRt[min]);
//检查其邻节点, 若final为FALSE,更新dist和path信息
R = G->platList[min].first;
while(R){
if(min == R->iPF){
//更新dist信息
if(distRt[R->jPF] == -1 || distRt[R->jPF] > distRt[min] + R->len){
distRt[R->jPF] = distRt[min] + R->len;
printf("%s的distRt已更新为:%lf\n", G->platList[R->jPF], distRt[R->jPF]);
//更新path信息
pathRt[R->jPF] = R->iPF;
}
R = R->iLink;
}else if(min == R->jPF){
//更新dist信息
if(distRt[R->iPF] == -1 || distRt[R->iPF] > distRt[min] + R->len){
distRt[R->iPF] = distRt[min] + R->len;
printf("%s的distRt已更新为:%lf\n", G->platList[R->iPF], distRt[R->iPF]);
//更新path信息
pathRt[R->iPF] = R->jPF;
}
R = R->jLink;
}
}
}
printf("\n===============================\n");
color(6);
printf("\n经迪杰斯特拉算法,可求得从%s至%s班车的最短路径大小为:%lf", G->platList[end],
G->platList[begin], distRt[end]);
i = end;
printf("\n\n其最短路径为:");
while(i != -1){
printf("%s", G->platList[i].name);
i = pathRt[i];
if(i != -1) printf("-->");
}
printf("\n");
}