您的位置:首页 > 理论基础 > 数据结构算法

数据结构—C语言:校园导航系统(最短路径两种算法:暴力枚举以及Dijkstra)

2018-12-12 18:40 381 查看

本人是某大学计算机的菜鸡,在数据结构上机课作业完成过程中,曾上网找了很多类似代码寻找思路,但是网上的代码太繁琐,而且都不是很好理解,因此在自己完成以后就写了这么一个博客,提供一种比较简单的程序代码,希望对那些还在数据结构中头痛的同学一点帮助。
        问题描述:设计以校园导游程序,为来访的客人提供各种信息查询服务。

设计要求:

(1)设计自己所在学校的校园平面图(所含景点不少于十个),顶点信息包括名称、简介等,边的信息包括路径长度等。

(2)为来访的客人提供景点信息查询服务。

(3)为来访的客人提供从当前顶点出发前往景点的路线查询服务,包括最短路径及有可能的简单路径。
 附图:

其实整个题目很简单,主要就是求最短路径的算法问题,在这里由于这个题需要输出所有路径,因此直接选取暴力枚举的方法,把所有的路径都给枚举出来,最后将最小的路径保存起来,最后单独进行输出就好:

[code]     if(b==w) {                                  //如果找到终点则进行输出,否则继续查找
for(p=0;p<k;p++){
printf("%d->",G->a

); } printf("%d ",G->a[k]); printf("路线总长:%dkm\n",sum); if(sum<G->minrude){ //若当前路径总长小于最小值,则对最短路径进行更新 G->r=k; G->minrude=sum; for(p=0;p<=k;p++){ G->min[p]=G->a[p]; } } return ; } else{ for(j=1;j<=10;j++){ if(G->arc[b][j]<5000&&G->vexs[j].park==0){ k++; G->a[k]=j; sum+=G->arc[b][j]; G->vexs[j].park=1; RudeGraph(G,j,w,k,sum); //通过递归对所有路径进行深度搜索 k--; //递归返回这一层后对顶点信息进行重新初始化 G->vexs[j].park=0; sum-=G->arc[b][j]; } } }

值得注意的是,这段暴力枚举的代码使用了邻接矩阵的思想,从邻接矩阵的第一行第一个点对后面点的不断递归查找,返回上一层时候对顶点信息初始化为递归前的状态还是比较细节的。

完整代码如下:

[code]#include <stdio.h>
#include <stdlib.h>

#define M 5000              //假设两顶点之间没有路径,用5000来表示

typedef struct vexsinfo     //存放顶点信息的结构体
{
int park;               //访问的标志,park=0是未被访问过
int num;                //景点的编号
char name[32];          //景点的名称
char introduction[256]; //景点的介绍
}vexsinfo;

typedef struct MGraph
{
int r;                  //记录最短路径访问过的景点数目
int minrude;            //记录最短路径的长度
int min[50];            //记录最短路径经过的顶点信息
int a[50];              //记录路线的数组
vexsinfo vexs[50];      //存放顶点编号的数组,用vexsinfo结构体的变量vexsinfo定义,可以用
//该数组存放顶点信息
int arc[50][50];        //存放两点之间权值的邻接矩阵
int v,e;                //定点数和边数
} MGraph;

MGraph* CreateGraph()
{
MGraph *G;
int i,j,k;
G=(MGraph*)malloc(sizeof(MGraph));

//初始化访问标志
for(i=0;i<10;i++){
G->vexs[i].park=0;
}

//初始化顶点数目和路线数目
G->v=10;
G->e=13;

//给景点数组编号
for(i=1;i<=G->v;i++)
G->vexs[i].num=i;
for(j=1;j<=10;j++)
for(k=1;k<=10;k++)
{
G->arc[j][k]=M;
}

//初始化矩阵,赋予每条边权值
G->arc[1][2]=G->arc[2][1]=1;
G->arc[1][3]=G->arc[3][1]=3;
G->arc[1][10]=G->arc[10][1]=8;
G->arc[2][6]=G->arc[6][2]=2;
G->arc[4][3]=G->arc[3][4]=1;
G->arc[4][5]=G->arc[5][4]=1;
G->arc[9][5]=G->arc[5][9]=2;
G->arc[6][7]=G->arc[7][6]=1;
G->arc[7][8]=G->arc[8][7]=2;
G->arc[10][7]=G->arc[7][10]=3;
G->arc[8][9]=G->arc[9][8]=2;
G->arc[8][10]=G->arc[10][8]=2;
G->arc[9][10]=G->arc[10][9]=3;

//初始化顶点信息
strcpy(G->vexs[1].name ,"校  门");
strcpy(G->vexs[2].name ,"综合楼");
strcpy(G->vexs[3].name ,"科技馆");
strcpy(G->vexs[4].name ,"月牙湖");
strcpy(G->vexs[5].name ,"咖啡屋");
strcpy(G->vexs[6].name ,"篮球场");
strcpy(G->vexs[7].name ,"体育馆");
strcpy(G->vexs[8].name ,"图书馆");
strcpy(G->vexs[9].name ,"学生活动中心");
strcpy(G->vexs[10].name ,"三炷香");
strcpy(G->vexs[1].introduction ,"曾经是亚洲第一大校门,现因临沂大学重建以后成为亚洲队二大校门");
strcpy(G->vexs[2].introduction ,"老师和领导们办公的地方");
strcpy(G->vexs[3].introduction ,"里面有学校的校史馆,记录着杭电发展的历史");
strcpy(G->vexs[4].introduction ,"学校里面唯一的湖,旁边有一片草地,是情侣们经常出没的地方,里面有许多鸭子游来游去");
strcpy(G->vexs[5].introduction ,"咖啡屋是学生在运营的,里面每天都会有学生和老师在学习和娱乐");
strcpy(G->vexs[6].introduction ,"篮球热爱者的天堂,篮球比赛都在这里举办");
strcpy(G->vexs[7].introduction ,"很多明星来开演唱会时会在体育馆内进行,其次篮球比赛决赛、开学典礼等也会在体育馆举行");
strcpy(G->vexs[8].introduction ,"图书馆高12层,是杭电教学区内最高的建筑物,是热爱学习的同学们的圣地");
strcpy(G->vexs[9].introduction ,"社团活动和很多晚会举办的地方");
strcpy(G->vexs[10].introduction ,"位于学校教学区的正中央,是杭电的标志性建筑物之一");
return G;

}
void RudeGraph(MGraph *G,int b,int w,int k,int sum){
int p,j,n;

if(b==w) {
for(p=0;p<k;p++){
printf("%d->",G->a[p]);
}
printf("%d  ",G->a[k]);
printf("路线总长:%dkm\n",sum);
if(sum<G->minrude){
G->r=k;
G->minrude=sum;
for(p=0;p<=k;p++){
G->min[p]=G->a[p];
}
}
return ;
}
else{
for(j=1;j<=10;j++){

if(G->arc[b][j]<5000&&G->vexs[j].park==0){
k++;
G->a[k]=j;
sum+=G->arc[b][j];
G->vexs[j].park=1;
RudeGraph(G,j,w,k,sum);    //通过递归对所有路径进行深度搜索
k--;                       //递归返回这一层后对顶点信息进行重新初始化
G->vexs[j].park=0;
sum-=G->arc[b][j];
}

}
}

return ;
}

int main(void)
{
int c,i,p,k;
MGraph *T;
T=CreateGraph();
while(1){
printf("**********************************\n");
printf("欢迎来到******大学景点信息服务系统\n");
printf("1.景点信息查询\n");
printf("2.路线查询服务\n");
printf("3.退出\n");
printf("**********************************\n");
printf("请选择你要查询的功能:\n");

scanf("%d",&c);
if(c==1){
printf("**********************************\n");
printf("******大学共有如下十处景点:\n");
for(i=1;i<=10;i++){
printf("%d.",T->vexs[i].num);
printf("%s:    ",T->vexs[i].name);
printf("%s\n",T->vexs[i].introduction);
}
}

else if(c==2){
printf("**********************************\n");
printf("请输入当前景点编号和你想要去的景点编号:\n");
printf("(注:景点编号可在功能1内查询)\n");
int b,w;
//初始化访问标志
for(i=0;i<10;i++){
T->vexs[i].park=0;
}
scanf("%d %d",&b,&w);
while(b<1||b>10||w<1||w>10){
printf("输入错误,请重新输入:\n");
scanf("%d %d",&b,&w);
}
if(b==w){
printf("您已经在此景点,请重新输入:\n");
scanf("%d %d",&b,&w);
}
else{
T->a[0]=b;
T->vexs[b].park=1;
printf("从景点%d到景点%d共有如下路径:\n",b,w);
RudeGraph(T,b,w,0,0);
printf("最短路径为:\n");
for(p=0;p<T->r;p++){
printf("%d->",T->min[p]);
}
printf("%d  ",T->min[T->r]);
printf("路线总长:%dkm\n",T->minrude);
T->minrude=100;                        //重新初始化最短路径长度

}

}
else if(c==3) break;
else printf("输入错误,请重新输入:\n");
}
printf("祝您生活愉快,再见^v^");
return 0;
}

下面提供Dijkstra算法的伪代码:

和暴力枚举相比,Dijkstra的代码只是在算法和最后输出时有所不同,在顶点信息中多加了一个变量存储当前顶点的直接前驱节点,其它地方代码段上的注释应该足够明确,当然算法的思想还是需要看代码前提前掌握的。

[code]typedef struct vexsinfo //顶点信息
{
int park; //访问的标志
int num; //景点的编号
int prenum; //记录当前顶点的前一个顶点编号
int quanzhi; //顶点的权值
char name[32]; //景点的名称
char introduction[256]; //景点的介绍
}vexsinfo;

typedef struct MGraph
{
vexsinfo vexs[50];//顶点表
int arc[50][50];//边表
int v,e;//定点数和边数
} MGraph;

void RudeGraph(MGraph *G,int b,int k){         //迪杰斯特拉求最短路径
int i,j,min,minu;
min=1000;
for(j=1;j<=10;j++){
if(G->arc[b][j]<5000&&G->vexs[b].quanzhi+G->arc[b][j]<G->vexs[j].quanzhi&&G->vexs[j].park==0){
G->vexs[j].prenum=b;               //更新当前顶点的直接前驱节点
G->vexs[j].quanzhi=G->vexs[b].quanzhi+G->arc[b][j];   //对顶点的权值进行更新
}
}
G->vexs[b].park=1;

for(i=1;i<=10;i++){                        //找到目前权值最小的点的编号存储minu
if(G->vexs[i].quanzhi<min&&i!=b&&G->vexs[i].park==0){
min=G->vexs[i].quanzhi;
minu=i;
}
}
k++;
if(k<10)
RudeGraph(G,minu,k);                   //对当前权值最小的点进行递归
else                         //有个记录前驱编号的还没用到,先求出最短路径再实现输出
return ;
}

最短路径的输出:
 

[code]                 //初始化顶点权值
for(i=0;i<=10;i++){
T->vexs[i].quanzhi=5000;
}
T->vexs[b].prenum=-1;           //没有前驱结点将其设为-1
T->vexs[b].park=0;
T->vexs[b].quanzhi=0;
RudeGraph(T,b,1);
printf("从景点%d到景点%d最短路径为:\n",b,w);
b=w;
j=0;
while(T->vexs[b].prenum!=-1){      //从终点向前查找前驱节点并保存在数组里
a[j]=T->vexs[b].prenum;
b=T->vexs[b].prenum;
j++;
}
printf("最短路径为:\n");
for(i=j-1;i>=0;i--){             //对数组逆向输出,从而找到最短路径
printf("%d->",a[i]);
}
printf("%d\n",w);
printf("路径长度为:\n");
printf("%d\n",T->vexs[w].quanzhi);
[p] 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐