内容简介:
这是一个我大二最近的数据结构课设题目,拿出来和大家分享分享,如有错误之处劳烦大家帮忙更正呀
题目如下:
需求功能分析:
- 查询任一地点的基本信息
- 查询任意两个地点之间的最短路径及其长度
特别注意:我并没有将图中“测试数据”一栏中的第一和第二点加入需求中,我的理由是:程序的对象是用户,类似于初始化地图信息的操作应该由设计者本身去完成,而不是交给用户,这极大影响了用户体验;如果我一开始就按照题目上的要求进行设计的话,完成之后拿给同学进行测试的话,那么对方还需要给地图进行初始化,这要输入很多信息,可能对方刚输入一半就放弃了你的测试
逻辑结构分析:
- 我们知道,校园中的道路往往都是双向通行的,所以我们可以将校园的各个地点看做是一个一个顶点,而两地点之间的道路看做是两个顶点之间的边,那么道路的长度就是边的权值
- 由此我们不难得出校园地图的逻辑结构很显然是一个无向网,并且是加权无向网
物理存储结构设计:
- 根据上面的逻辑结构分析,我们知道校园地图抽象为一个加权无向网,那么对于无向网而言,在已有的数据结构中,邻接矩阵是最为适合无向网的存储工作的,邻接矩阵十分便于访问图中的各个顶点,所以整个地图地点之间的关联关系和权值均存储在邻接矩阵中,说通俗点也就是个二维数组
- 因为各个地点还有各自的名称、代号和简介,那么就将名称、代号和简介封装成为一个结构体Vex,Vex中具有名称、代号和简介三个成员变量,用Vex[vexsnum]结构体数组存储地图中所有地点的基本信息(这里的vexnum就是顶点个数),下文将Vex[vexsnum]这个数组简称为顶点信息数组
- 最后再将顶点信息数组和邻接矩阵封装为一个结构体Graph,Graph中具有顶点信息数组和邻接矩阵两个成员。至此,对校园地图各个地点的信息和关联关系的存储问题均已解决
- 在设计上面两个结构体之前,还需要预编译时定义两个常量,分别是顶点个数和边数,作为顶点信息数组和邻接矩阵的个数参数,这里给出Vex和Graph结构体的基本实现代码
#define MAXVEX 15 //最大顶点数,应由用户定义
#define NUMBER 22 //最大边数,应由用户定义
typedef string VertexName; //顶点名称应由用户定义
typedef char replace; //顶点代号应由用户定义
typedef string info; //顶点简介应由用户定义
typedef struct {
VertexName name; //地点名称
replace ch; //地点代号
info str; //地点简介
}Vexs;
typedef int EdgeType; //边上的权值类型应由用户定义
typedef struct {
Vexs vexs[MAXVEX]; //顶点信息数组
EdgeType arc[MAXVEX][MAXVEX]; //邻接矩阵,可看作边
int numVertexes, numEdges; //图中当前的顶点数和边数
}Graph;
特别注意:此处的typedef是对后面声明变量的“数据类型”起了一个别名,而这个别名就是“变量名”;比如typedef string info;这个语句,那么以后想用string类型来声明变量可以用别名来替代,例如:声明一个string类型的变量a,那么就可以用以下语句进行声明
//声明了一个string变量a
info a;
//等价于
string a;
算法设计:
1 . locates定位函数:
因为我们每一个地点是使用邻接矩阵而存储的,那么也就是说地点 A 对应邻接矩阵的行号列号均是 i ,这里的 i 是整数,而我们的地点名称为string类型所存储(此处请参考上文的Vex结构体声明),所以我们需要一个将string类型的地点名称可以转化为对应邻接矩阵上的整数行号和列号,这样子才能通过输入一个string类型的地点名称,通过转定位函数成换整型的行号和列号之后,才能方便地访问到邻接矩阵和顶点信息数组的对应信息。
这里给出locates函数的具体实现:
int locates(Graph *g, string ch) {
int i = 0;
for (i = 0; i < g->numVertexes; i++) {
//g->numVertexes为当前顶点数
if (g->vexs[i].name == ch) {
//g->vexs[i].name为各个地点的名称
break;
}
}
if (i >= g->numVertexes) {
return -1;
}
return i;
}
2 . createGraph创建地图无向网函数:(初始化)
这里的初始化函数将用预先准备好的校园地点和地点之间的关联关系来进行无向网的搭构任务,所以我准备了以下的信息
选择了15个广东理工学院校园地点,分别为:
振华楼、学院练车场、美食广场、春晖苑、学校游泳池、东区足球场、翔中堂、健身房、电工房、科技广场、
生活服务中心、桃李苑、图书馆、田径场、体育馆
设置了22条边关联:(这里的边是无向边,后面数字代表边的权)
振华楼 <->学院练车场 30
振华楼 <-> 美食广场 20
振华楼 <-> 春晖苑 25
振华楼 <-> 学校游泳池 50
学院练车场 <-> 美食广场 10
美食广场 <-> 春晖苑 5
学校游泳池 <-> 东区足球场 5
学校游泳池 <-> 翔中堂 30
东区足球场 <-> 春晖苑 50
东区足球场 <-> 健身房 35
翔中堂 <-> 健身房 7
翔中堂 <-> 电工房 20
健身房 <-> 电工房 15
电工房 <-> 科技广场 50
电工房 <-> 生活服务中心 100
科技广场 <-> 图书馆 35
科技广场 <-> 田径场 10
生活服务中心 <-> 图书馆 40
特别注意:上面我没有写代号和简介,是为了简洁文章长度,因为原理是和地点名称一样的,均用一个一维数组来进行存储
以下给出预先将上述信息存储好的代码片段
//事先把地图信息存储起来
//地点名称
VertexName vexname[15] = {
"振华楼",
"学院练车场",
"美食广场",
"春晖苑",
"学校游泳池",
"东区足球场",
"翔中堂",
"健身房",
"电工房",
"科技广场",
"生活服务中心",
"桃李苑",
"图书馆",
"田径场",
"体育馆"
};
//地点代号
replace vexch[15] = {
'Z','L','M','H','Y','Q','X','J','D','K','S','T','G','C','P'
};
//地点简介
info vexstr[15] = {
"振华楼是信息技术学院学员的主要活动场所,内置教室数百间,室内硬件配置齐全,当为模范教学楼!",
"学院练车场是与学校共同合作的一个校外商家,致力于为学生提供物美价廉的考驾照之旅,练车场位于校内,十分方便学生全天候练车!",
"美食广场位于广东理工学院东区区域,与春晖苑相邻,其中店家琳琅满目,数不胜数,风格深受学生欢迎,是校园的一处好栖息地!",
"春晖苑也被称之为东区食堂,与美食广场共同提供了学生们的日常餐饮生活,相对比与美食广场而言,春晖苑的装饰更为古风一些!",
"学校游泳池位于学校的东区区域,泳池是室内的,所以在任何时间段都十分适合学生下水,当然夏日泳池的plmm才是不可多得的一道风景线!",
"东区足球场,与学校游泳池相邻,有着良好的草地质感,给予运动员最舒适最安全的比赛场地,见证了无数广理足星的诞生!",
"翔中堂也被称之为礼堂,翔中堂主要作为大型活动的场地,内部有覆盖全场的空调,观众席十分豪华,并且座椅多达两层楼之多!",
"健身房位于礼堂的对角处,它是学生健身爱好者的天堂,内部硬件设施完善,安全设施齐全,如果店家可以免费让学生体验,再好不过了!",
"电工房位于校园的中间部分,当学生们宿舍发生电路问题时,都可以求助电工房来进行修理,当然电工一般是十分忙绿的,毕竟只有一所电工房!",
"科技广场是我校的重要场所,其广场里的科技之星雕塑更是我校的标示性建筑,寓意着师生不断创新,追求真理的科技之心!",
"生活服务中心也被学生们称之为西区超市,因为其建筑和超市并无两样,除此之外,最大的特色就是网红街,试想,一个宁静的夜晚,在满是星星灯下的你和好朋友们畅聊着星辰大海,是多么惬意的事情!",
"桃李苑位于西区区域,也称之为西区饭堂,不过其内部的装饰还是店家的款式,都比春晖苑要好一些!",
"图书馆位于我校正门的正前方,正所谓一进门就得以闻其书香气,图书馆是追求知识的天堂,里面有着一群志同道合,向往远方的青年少女,一起为自己的未来而去奋斗!",
"田径场是我校举行校运会的主要场地,有着400米的塑胶跑道,为西区的学生们提供了不可多得的课后锻炼场所!",
"体育馆与田径场相邻,这是我校唯一的室内运动馆,内有一个篮球场和四个羽毛球场,如果能再多一些室内场地,那将十分深受学生们的欢迎!",
};
//初始化地点名称1
string loadingOne[22] = {
"振华楼",
"学院练车场",
"美食广场",
"振华楼",
"振华楼",
"振华楼",
"学校游泳池",
"东区足球场",
"学校游泳池",
"东区足球场",
"翔中堂",
"翔中堂",
"健身房",
"电工房",
"电工房",
"科技广场",
"科技广场",
"田径场",
"图书馆",
"图书馆",
"桃李苑",
"生活服务中心"
};
//初始化地点名称2
string loadingTwo[22] = {
"学院练车场",
"美食广场",
"春晖苑",
"美食广场",
"春晖苑",
"学校游泳池",
"东区足球场",
"春晖苑",
"翔中堂",
"健身房",
"健身房",
"电工房",
"电工房",
"科技广场",
"生活服务中心",
"图书馆",
"田径场",
"体育馆",
"田径场",
"桃李苑",
"生活服务中心",
"图书馆"
};
//初始化地点路程
int loadingNum[22] = {
30,10,5,20,
25,50,5,50,
30,35,7,20,
15,50,100,35,
10,5,10,20,
25,40
};
由此我们可以知道vexname、vexch、vexstr这三个数组的下标是一一对应的关系,即vexname[5]对应着vexch[5]和vexstr[5];并且不难看出loadingOne、loadingTwo、loadingNum这三个数组也是一一对应的关系,这种关系和前面三个数组的关系是一样的。
那么用于初始化的信息准备好了之后,就可以开始将校园地图抽象为无向网啦,这里给出createGraph函数的完整代码,此函数中调用了locates定位函数,不清楚locates定位函数的道友们可以回头去看看哦
#define INF 9999999 //定义一个无穷大数
void createGraph(Graph *g) {