话不多说,先上主要代码,后面是实验报告
//本实验主要实现三个功能,分别为查询地点信息,搜索起点到目标点的最短路径以及设计一条施工方案使得管道穿过所有地点且路径最短。
//分别对应的算法为蛮力搜索,迪杰斯克拉算法,克鲁斯卡尔算法。
void chaxun (INTR q[],int x){//蛮力搜索,事先储存好相应数据,查询时通过字符串比较,编号查询等方式查询所需地点信息
int i;
char str[100];
if(x==1){
cout<<"请输入名称:";
scanf("%s",str);
cout<<endl;
for(i=1;i<=23;i++){//根据名称查询
if(strcmp(q[i].name,str)==0){
cout<<"地点:";
cout<<q[i].place<<endl;
cout<<endl;
cout<<"简介:";
cout<<q[i].summar<<endl;
}
}
}
else if(x==2){
int f;
cout<<"请输入编号:";//根据编号查询
scanf("%d",&f);
cout<<endl;
cout<<q[f].name<<endl;
cout<<endl;
cout<<"地点:";
cout<<q[f].place<<endl;
cout<<endl;
cout<<"简介:";
cout<<q[f].summar<<endl;
}
else
cout<<"输入错误!"<<endl;
}
void KRUSKAL(int m[][24],RESERVE G[],INTR q[]){//克鲁斯卡尔算法,属于贪心算法,先对权值边排序,之后再依次选入,如果加入的边不形成环则选入,反之,则舍弃。
int i,j,sn,sm;
int temp1,temp2,temp3;
int parent[25];
int SUM=0;
int k=1,l=1;
for(i=1;i<50;i++){//对边集依据权值进行排序
G[i].port=INFINITY;
G[i].first=INFINITY;
G[i].last=INFINITY;
}
for(i=1;i<=23;i++){//冒泡排序
for(j=1;j<=23;j++){
if(k<j&&m[i][j]!=INFINITY){
G[l].port=m[i][j];
G[l].first=i;
G[l].last=j;
l++;
}
}
k++;
}
for(i=1;i<=34;i++){
for(j=1;j<=34-i;j++){
if(G[j].port>G[j+1].port){
temp1=G[j+1].port;
G[j+1].port=G[j].port;
G[j].port=temp1;
temp2=G[j+1].first;
G[j+1].first=G[j].first;
G[j].first=temp2;
temp3=G[j+1].last;
G[j+1].last=G[j].last;
G[j].last=temp3;
}
}
}
for(i=1;i<=23;i++)//初始化数组为0
parent[i]=0;
for(i=1;i<=33;i++){//循环每一条边
sn=FINDS(parent,G[i].first);
sm=FINDS(parent,G[i].last);
if(sn!=sm){//如果相等,说明此边形成了环
parent[sn]=sm;//将此边的结尾顶点放入下标为起点的parent中,表示此顶点已经在生成树的集合中
// cout<<G[i].first<<"\t"<<G[i].last<<"\t"<<G[i].port<<endl;
cout<<q[G[i].first].name<<"--->"<<q[G[i].last].name<<" "<<G[i].port<<endl;
SUM+=G[i].port;
}
}
cout<<endl;
cout<<"总长度最短为:"<<SUM<<"米."<<endl;
}
int FINDS(int parent[],int f){
while(parent[f]>0)
f=parent[f];
return f;
}
void Dijestra(int start,int finalt,int w[][24],INTR q[]){//迪杰斯克拉算法
int mint,i,j,c,d;
int p[100],z[100],book[100],dis[100];
memset(p,-1,sizeof(p));//初始化
memset(z,0,sizeof(z));
memset(book,0,sizeof(book));
for(i=1;i<=23;i++) //选择与起点相邻的点
{
dis[i]=w[start][i];
if(dis[i]<INFINITY)
p[i]=start;//将相邻点标记
}
book[start]=1;//标记已经经过的点
for(i=1;i<23;i++){
mint=INFINITY;
for(j=1;j<=23;j++){//每次找出距离起点最近的点
if(book[j]==0&&dis[j]<mint)
{
mint=dis[j];
c=j;
}
}
book[c]=1;//标记已经经过的点
for(d=1;d<=23;d++){
if(book[d]==0&&dis[d]>dis[c]+w[c][d]){//通过该点更新其他点的路径
p[d]=c;//存入更新的边
dis[d]=dis[c]+w[c][d];
}
}
}
d=finalt;
i=1;
while(p[d]!=start){//正序输出
z[i++]=p[d];
d=p[d];
}
cout<<endl;
c=i-1;
cout<<"路线为:"<<endl;
cout<<q[start].name<<"--->";
for(i=c;i>=1;i--){
cout<<q[z[i]].name<<"--->";
}
cout<<q[finalt].name<<endl;
cout<<"最短路径为:"<<dis[finalt]<<"米."<<endl;
}
1 问题描述
智慧校园系统主要开发目的是为人们进行校园观景提供路线指导,整个系统包括景点信息查询,最短路径指导,施工路线选择三部分,景点信息查询可支持名称查询和编号查询,最短路径指导可支持对开车和步行两种方式提供路线。施工路线可以查找出连通所有景点建筑物并且 路径最短的路线。整个智慧校园系统满足设计要求,可以提供更加快捷方便的信息,为游客节省时间与精力,提升旅游体验。
2 需求分析
2.1 数据需求
建立无向图来表示校园建筑,顶点为建筑物,边表示建筑物之间的路径,所需数据主要为路径的长度,建筑物的信息,包括名称,简介,地点 ,标号等信息。因为有23个建筑物,所以需要23个建筑物的信息和所有边的数据。
路径权值:int m[24][24] int n[24][24]
建筑物名称 char name[20]
建筑物简介 char summar[100]
建筑物地点 char place[100]
建筑物标号 由二维数组m的行号和列号从1到23表示。
2.2 功能需求
首先给出具体的功能说明,最后给出总的功能模块图。
1.为任一初次来的客人提供路径查询服务,根据当前客人所在位置,客人要访问的目标位置,给出一条最短路径,最短路径还要考虑,客人是开车还是步行,所提供的最短路径不同。
2.实现对任一建筑物的查询,查询结果包括建筑物名称,简介,在校园的大概位置。
3.提供一个施工方案,能够连通所有建筑物且长度最短。
2.3 开发环境
在CodeBlocks13.12上利用c语言实现
3 概要设计
3.1抽象数据类型智慧校园的定义
ADT campus{
数据对象:v属于校园建筑点,e属于建筑物之间的路径。
数据关系:R={VR},VR={<v,w>|v,w属于V且P(v,w),<v,w>表示从v到w的路径}
基础操作:
jiemian();
操作结果:打印出路径导航功能项
chunshu1(m,q);
初始条件:m为存图的数组,q为存建筑物信息的结构体。
操作条件:将建筑物的信息和路径的权值存入图中。
Chunshu2(m);
初始条件:m为存图的数组。
操作结果:将建筑物之间路径的权值存入图中。
Dijestra(start,finalt,m,q);
初始条件:存在起始点start,存在终点finalt,存在建筑物信息的结构体q。
操作结果:求出一条从起始点start到终点finalt的路径
chaxun(q,x);
初始条件:存在建筑物信息的结构体q,模式选择数x。
操作结果:根据选择的模式查找出对应的建筑物的信息。
KRUSKAL(m,G,q);
初始条件:存在存图的数组,存在边集的结构体G,存在建筑物信息的结构体q。
操作结果:求出一条施工路径且这条路径总长度最短。
}
3.2算法概要设计
- jiemian();//打印导航列表
2. while(b!=0){//功能循环,实现输入错误返回以及使用功能
3. chunshu1(m,q);//存图
4. chunshu2(n);//存图
5. 输入a选择功能
6. switch(a){//选择功能
7. case 1:
8. 输入f选择模式
9. if(f==1)
10. start,finalt赋值
11. Dijestra(start,finalt,m,q);//最短路径
- else if(f==2)
- start,finalt赋值
14. Dijestra(start,finalt,n,q);//最短路径
15. else
16. "输入错误!"
17. end if
18. break;
19. case 2:
20. while(k!=0)
21. 选择模式,赋值x
22. chaxun(q,x);
23. 给c赋值
24. if(c!=0)
25. k=c;
26. else
27. break;
28. end if
29. end while
30. break;
31. case 3:
32. KRUSKAL(m,G,q);//寻找施工方案
33. break;
34. end switch
35. 赋值e
36. b=e;
37. end while;
38. return 0;
4 详细设计
4.1存储结构:
typedef struct INTRODUCE{//存入建筑物信息,包括名称,简介,位置
char name[20];
char summar[100];
char place[100];
}INTR;
struct RESERVE{//克鲁斯卡尔算法所需排序的结构,包括权值,起点,终点
int port;
int first;
int last;
};
int m[24][24] //记录建筑物之间的路径长度即权值
4.2 导航功能表
输入:无。
输出:一张导航功能表
jiemian(){
1.Print(打印导航的功能表)
2.}
4.3 存储步行图数据
输入:二维数组m,表示建筑物信息的结构体q。
输出:存储了有效数据的图
chunshu1(m,q){
1.for i<—1 to 23//初始化
2. for j<—1 to 23
3. m[i][j]<—INFINITY;
4. End for
5.End for
6.m[i][j]<—对有效数据依次存入
7.q<—对建筑物信息依次存入
8.}
4.4 存储行车图数据
输入:二维数组m,表示建筑物信息的结构体q。
输出:存储了有效数据的图
chunshu2(m){
for i<—1 to 23//初始化
for j<—1 to 23
m[i][j]<—INFINITY;
4. End for
5.End for
6.m[i][j]<—对有效数据依次存入
7.}
4.5 最短路径
输入:含权的有向图G=<V,E>,V=(1 to 23),输入的起始点,终点。
输出:起始点到终点的最短距离
Dijestra(start,finalt,m,q){
1. X={1};Y<—V-{1};e[1]<—0
2. For y<—2 to n
3. If y相邻于1 then e[y]<—length[1,y]
4. Else e[y]<—1 to n-1
5. End if
6.End for
7.For j<—1 to n-1
8. 令 y属于Y 使得e[y]为最小
9. X<—X并|y| {将顶点y加入X}
10. Y<—Y并|y| {将顶点y从Y中删除}
11. For 每条边(y,w)
12. If w属于Y and e[y]+length[y,w]<e[w] then
13. e[w]<—e[y]+length[y,w]
14. End for
15.End for
}
4.6 KRUSKAL(m,G,q);
输入:包含23个顶点的含权连通无向图m,存有边信息的G,存有建筑物信息的q。
输出:由m生成的最小耗费生成树T组成的边的集合。
1.G<—存入权值信息m,以及边的起点和终点。
2.按非降序权值将G排序
3.For 每条边v属于V
4. Makeset(|v|) 使每个点单独成一个集合
5. End for
6.T=空
7.While T<n-1
8. 令(x,y)为E中的下一条边
9. If FIND(x)!=FIND(y) then
10. 将(x,y)加入T
11. 将x连接y
12. End if
13.End while
5 系统运行及结果分析
5.1 最短路径查询
利用迪杰斯克拉算法完成对最短路径的搜索,函数的输入需要当前所在地点以及想要去的地点,本功能可以实现两种搜索模式,分别为步行和开车提供不同的路线,当启动程序时可以选择功能模式,若选择的模式不正确,则会输出错误提醒,还会重新提供功能选择,在搜索最短路径时,还会记录路径的长度,最后输出最短路径的长度以及最短路线,本功能可以满足用户对搜索最短路径的基本需求,还可以在用户选择功能模式错误时做出相应反应,整体满足要求。
例如图5.1选择功能1,模式1为步行最短路径查询,提供了12到16的最短路径为学生宿舍六号楼—>图书馆,最短路径为280米。当选择模式为2开车最短路径查询时,提供的最短路径为学生宿舍六号楼—>主楼—>教学三号楼—>地球科学博物馆—>钱圆金融博物馆—>图书馆。当选择的模式为其他时,输出“输入错误”,重新进行功能选择。
5.2 地点信息查询
本功能利用已经存好数据的结构体q,通过蛮力搜索的方法查找想要的建筑物的信息,由于建筑物有名称和编码两种形式,所以本功能可以使用名称查询和编号查询两种模式,在查询时可以选择查询模式,当输入的查询模式不正确时会有错误提醒,并且会让人重新选择功能模式,再选择模式查找。利用字符串的一些操作函数等可一找出相应的地点,最后打印出建筑物的名称,地点,简介等信息。
例如图5.2,当选择功能2,模式1时。为根据名称查询,查的信息为名称,地点,简介等信息输出0当选择模式为2时,为根据编号查询,查的信息为名称,地点,简介等信息输出。当选择的模式为其他时,输出“输入错误”,重新进行功能选择。
5.3 施工路径
本功能利用克鲁斯卡尔算法来寻找最小耗费生成树,先将带权值的边进行排序,依次选取最小的边,再判断是否形成环,不形成环则加入集合,由于边的选取是每次找最小权值的边,所以边的选取并不连续,在输出时依次输出边以及它的权值,最后输出它总长度为多长。整个功能完全,满足实验要求。
6 总结与思考
智慧校园系统体现了一个管理系统的需求分析、系统设计、数据结构设计、界面设计和开发实现的完整过程。本系统实现了在大量的校园景点中任意指定两个景点就能给出最短路径以及对建筑物信息的查询,施工方案的规划。在本程序的总体设计部分还给出了系统模块结构图,并对各个模块的设计过程进行了阐述。
其中最短路径的算法是利用迪杰斯克拉算法,通过先寻找起始点的相邻的点,将其余点的值设为无穷,再将相邻的点的值设为路径长度,再选择通过相邻点且离起点最近的点,得到新的路径长度,与原来的路径长度进行比较,如果小于原来的长度,则更新路径长度的记录,再选择离起点最近的相邻点,按照上述步骤依次进行直到找出最短路径到终点。
克鲁斯卡尔算法是本实验我遇到的一个困难,一开始我错误的认为只需要判断所创造的集合中顶点是否有重叠就可以判断是否有环,但由于数据结构创建的不符合,使得生成的路径为森林,通过查阅书籍学习,了解到了利用parent数组判断有无环,我的理解是将生成的对应的parent数组的下标和值可以看成一组群,当群的子群中含有循环群时,则可以形成环,现实情况也是如此。
在这次的试验中,一步步的解决了课题选定、资料查找、各模块的算法设计、各模块和主程序的程序编辑、最后的调试等步骤,完成了整体设计。在确定了大致上的方向后,我也遇到了很多细节方面的问题,通过查找资料,询问同学等方法,一个个问题都最终解决了.通过这次课程设计,使我充分认识到了自己一些方面的不足,同时经过课程设计时跟同学的不断讨论,使我对数据结构和算法有了更深入和更全面的认识。
通过本次课程设计,也暴露了我很多学习上的误解.每门课都是要踏踏实实的学的,而不只是流于形式,对算法的理解不能只是停留在书本上的内容,不仅要对所学过的内容做到了然于心,还要对算法的核心进行理解与掌握。同时,还要扩展课外知识,计算机专业是一个不断飞速发展的行业,现有的知识有时并不能解决所面临的问题,需要知识的扩充与积累,只有脚踏实地,一步一个脚印才能有所收获。