|
|
|
|
#城市地铁导航系统
|
|
|
|
|
|
|
|
|
|
2023年6月25日
|
|
|
|
|
成员1:王昊 成员2:孙艺哲 成员3:张江楠 成员4:郭佳慧
|
|
|
|
|
|
|
|
|
|
##项目简介
|
|
|
|
|
|
|
|
|
|
这段代码是一个模拟上海地铁交通服务平台的程序,提供了最佳出行线路推荐和出行费用预估的功能。程序首先初始化地铁站点的数据,然后根据用户的输入,计算出最佳的出行线路和预估的费用。
|
|
|
|
|
下载地址:https://bdgit.educoder.net/mac76tib2/ddd.git
|
|
|
|
|
|
|
|
|
|
项目开发过程中采用 Kanban(看板)进行任务管理和分工协作,并使用 Git 对程序代码和文档进行版本管理。任务分工情况如下:
|
|
|
|
|
| 任务 | 设计 | 开发 | 测试 | 文档 |
|
|
|
|
|
|------|-----|------|------|-----|
|
|
|
|
|
| C1 | 王昊 | 王昊 | 张江楠 | 郭佳慧 |
|
|
|
|
|
| C2| 张江楠 | 张江楠 | 郭佳慧 | 孙艺哲 |
|
|
|
|
|
| C3 | 郭佳慧 | 郭佳慧 | 孙艺哲 | 王昊 |
|
|
|
|
|
| C4 | 孙艺哲 | 孙艺哲 | 王昊 | 张江楠 |
|
|
|
|
|
|
|
|
|
|
每个成员工作量(百分比):
|
|
|
|
|
| 王昊 | 张江楠 | 郭佳慧 | 孙艺哲 |
|
|
|
|
|
|----|---|----|----|
|
|
|
|
|
| 25 | 25 | 25 | 25 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
##需求分析
|
|
|
|
|
|
|
|
|
|
(1) 基于真实的地铁数据建立导航地图模型,编制成格式简单的数据文件包括城市线路名称、站点名称。
|
|
|
|
|
(2)系统能够读取地铁导航地图数据文件,建立地铁模型,也能够将模型输出成数据文件,以便验证模型的正确性。
|
|
|
|
|
(3)通过人机交互的方式输入起点和终点站名称,系统给出路径长度最短的导航路径,并给出换乘方案。
|
|
|
|
|
(4)能够读取不同的地铁导航地图进行功能测试。
|
|
|
|
|
|
|
|
|
|
##C1:定义结构体、创建文件
|
|
|
|
|
```
|
|
|
|
|
代码:#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#define MAX 1000
|
|
|
|
|
typedef struct node {
|
|
|
|
|
char a[100];
|
|
|
|
|
struct node* next;
|
|
|
|
|
}edgenode;
|
|
|
|
|
typedef struct {
|
|
|
|
|
char name[100];
|
|
|
|
|
edgenode* firstnode;
|
|
|
|
|
}vexnode;
|
|
|
|
|
typedef struct {
|
|
|
|
|
vexnode adjust[7];
|
|
|
|
|
int e, n;
|
|
|
|
|
}list;
|
|
|
|
|
list nm;
|
|
|
|
|
|
|
|
|
|
char position[100]="address.txt";
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
char s[100];
|
|
|
|
|
}filed;
|
|
|
|
|
filed fi[100];
|
|
|
|
|
void createfile(){
|
|
|
|
|
int i;
|
|
|
|
|
FILE* op;
|
|
|
|
|
op=fopen(position,"ab");
|
|
|
|
|
if(op==NULL){
|
|
|
|
|
printf("该文件未找到");
|
|
|
|
|
return ;
|
|
|
|
|
}
|
|
|
|
|
char strs[100];
|
|
|
|
|
for(i=0;i<7;i++){
|
|
|
|
|
printf("请输入:\n");
|
|
|
|
|
scanf("%s",strs);
|
|
|
|
|
fprintf(op,"%s\n",strs);
|
|
|
|
|
}
|
|
|
|
|
fclose(op);
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
##C2:初始化节点以及打印节点名称并通过邻接表和邻接矩阵来表示图的结构{41-151}
|
|
|
|
|
```
|
|
|
|
|
代码:void creatnode() {//对节点进行初始化
|
|
|
|
|
nm.e = 7;//边数
|
|
|
|
|
nm.n = 7;//站点数
|
|
|
|
|
FILE* op;
|
|
|
|
|
op=fopen(position,"rb");
|
|
|
|
|
if(op==NULL) {
|
|
|
|
|
printf("文件不存在");
|
|
|
|
|
}
|
|
|
|
|
int i=0;
|
|
|
|
|
while(1){
|
|
|
|
|
char strs[100];
|
|
|
|
|
if(fscanf(op,"%s",strs)!=EOF){
|
|
|
|
|
//printf("%s\n",strs);
|
|
|
|
|
strcpy(nm.adjust[i].name,strs);
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
else break;
|
|
|
|
|
}
|
|
|
|
|
fclose(op);
|
|
|
|
|
for (i = 0; i < nm.n; i++) {
|
|
|
|
|
nm.adjust[i].firstnode = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void printff(){
|
|
|
|
|
for(int i=0;i<nm.n;i++){
|
|
|
|
|
printf("%s\n",nm.adjust[i].name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void createlist() {
|
|
|
|
|
struct node *p;
|
|
|
|
|
//下面是肇嘉浜路的邻接表
|
|
|
|
|
p = (edgenode*)malloc(sizeof(edgenode));
|
|
|
|
|
strcpy(p->a, "东安路");
|
|
|
|
|
p->next = nm.adjust[0].firstnode;
|
|
|
|
|
nm.adjust[0].firstnode = p;
|
|
|
|
|
p = (edgenode*)malloc(sizeof(edgenode));
|
|
|
|
|
strcpy(p->a, "嘉善路");
|
|
|
|
|
p->next = nm.adjust[0].firstnode;
|
|
|
|
|
nm.adjust[0].firstnode = p;
|
|
|
|
|
p = (edgenode*)malloc(sizeof(edgenode));
|
|
|
|
|
strcpy(p->a, "徐家汇");
|
|
|
|
|
p->next = nm.adjust[0].firstnode;
|
|
|
|
|
nm.adjust[0].firstnode = p;
|
|
|
|
|
//下面是东安路的邻接表
|
|
|
|
|
p = (edgenode*)malloc(sizeof(edgenode));
|
|
|
|
|
strcpy(p->a, "肇嘉浜路");
|
|
|
|
|
p->next = nm.adjust[1].firstnode;
|
|
|
|
|
nm.adjust[1].firstnode = p;
|
|
|
|
|
p = (edgenode*)malloc(sizeof(edgenode));
|
|
|
|
|
strcpy(p->a, "上海体育场");
|
|
|
|
|
p->next = nm.adjust[1].firstnode;
|
|
|
|
|
nm.adjust[1].firstnode = p;
|
|
|
|
|
p = (edgenode*)malloc(sizeof(edgenode));
|
|
|
|
|
strcpy(p->a, "大木桥路");
|
|
|
|
|
p->next = nm.adjust[1].firstnode;
|
|
|
|
|
nm.adjust[1].firstnode = p;
|
|
|
|
|
//下面是上海体育场的邻接表
|
|
|
|
|
p = (edgenode*)malloc(sizeof(edgenode));
|
|
|
|
|
strcpy(p->a, "东安路");
|
|
|
|
|
p->next = nm.adjust[2].firstnode;
|
|
|
|
|
nm.adjust[2].firstnode = p;
|
|
|
|
|
p = (edgenode*)malloc(sizeof(edgenode));
|
|
|
|
|
strcpy(p->a, "上海体育馆");
|
|
|
|
|
p->next = nm.adjust[2].firstnode;
|
|
|
|
|
nm.adjust[2].firstnode = p;
|
|
|
|
|
//下面是嘉善路的邻接表
|
|
|
|
|
p = (edgenode*)malloc(sizeof(edgenode));
|
|
|
|
|
strcpy(p->a, "大木桥路");
|
|
|
|
|
p->next = nm.adjust[3].firstnode;
|
|
|
|
|
nm.adjust[3].firstnode = p;
|
|
|
|
|
p = (edgenode*)malloc(sizeof(edgenode));
|
|
|
|
|
strcpy(p->a, "肇嘉浜路");
|
|
|
|
|
p->next = nm.adjust[3].firstnode;
|
|
|
|
|
nm.adjust[3].firstnode = p;
|
|
|
|
|
//下面是大木桥路
|
|
|
|
|
p = (edgenode*)malloc(sizeof(edgenode));
|
|
|
|
|
strcpy(p->a, "东安路");
|
|
|
|
|
p->next = nm.adjust[4].firstnode;
|
|
|
|
|
nm.adjust[4].firstnode = p;
|
|
|
|
|
p = (edgenode*)malloc(sizeof(edgenode));
|
|
|
|
|
strcpy(p->a, "嘉善路");
|
|
|
|
|
p->next = nm.adjust[4].firstnode;
|
|
|
|
|
nm.adjust[4].firstnode = p;
|
|
|
|
|
//下面是徐家汇
|
|
|
|
|
p = (edgenode*)malloc(sizeof(edgenode));
|
|
|
|
|
strcpy(p->a, "肇嘉浜路");
|
|
|
|
|
p->next = nm.adjust[5].firstnode;
|
|
|
|
|
nm.adjust[5].firstnode = p;
|
|
|
|
|
p = (edgenode*)malloc(sizeof(edgenode));
|
|
|
|
|
strcpy(p->a, "上海体育馆");
|
|
|
|
|
p->next = nm.adjust[5].firstnode;
|
|
|
|
|
nm.adjust[5].firstnode = p;
|
|
|
|
|
//下面是上海体育馆
|
|
|
|
|
p = (edgenode*)malloc(sizeof(edgenode));
|
|
|
|
|
strcpy(p->a, "徐家汇");
|
|
|
|
|
p->next = nm.adjust[6].firstnode;
|
|
|
|
|
nm.adjust[6].firstnode = p;
|
|
|
|
|
p = (edgenode*)malloc(sizeof(edgenode));
|
|
|
|
|
strcpy(p->a, "上海体育场");
|
|
|
|
|
p->next = nm.adjust[6].firstnode;
|
|
|
|
|
nm.adjust[6].firstnode = p;
|
|
|
|
|
}
|
|
|
|
|
int cont[100][100];//邻接矩阵
|
|
|
|
|
void aaa(){
|
|
|
|
|
int i,j;
|
|
|
|
|
for(i=0;i<nm.n;i++){
|
|
|
|
|
for(j=0;j<nm.n;j++) cont[i][j]=MAX;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
##C3:创建邻接矩阵、打印邻接矩阵和执行Dijkstra算法{152-230}
|
|
|
|
|
```
|
|
|
|
|
void createjz(){//创建邻接矩阵函数
|
|
|
|
|
edgenode *p;
|
|
|
|
|
aaa();
|
|
|
|
|
int i;
|
|
|
|
|
for(i=0;i<nm.n;i++){
|
|
|
|
|
p=nm.adjust[i].firstnode;
|
|
|
|
|
while(p!=NULL){
|
|
|
|
|
int h;
|
|
|
|
|
for(h=0;h<nm.n;h++)
|
|
|
|
|
if(!strcmp(p->a,nm.adjust[h].name)) break;
|
|
|
|
|
cont[i][h]=1;
|
|
|
|
|
p=p->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void print() {
|
|
|
|
|
edgenode* p;
|
|
|
|
|
int i;
|
|
|
|
|
for(i=0;i<nm.n;i++){
|
|
|
|
|
printf("[%s]",nm.adjust[i].name);
|
|
|
|
|
p=nm.adjust[i].firstnode;
|
|
|
|
|
while(p!=NULL){
|
|
|
|
|
printf("-->[%s]",p->a);
|
|
|
|
|
p=p->next;
|
|
|
|
|
}
|
|
|
|
|
printf("\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
int num2=0;
|
|
|
|
|
int money=0;
|
|
|
|
|
void Dijkstra(int v1,int v2){
|
|
|
|
|
int dist[MAX],s[MAX],path[MAX];//s判断v1是否已经判断最短路径,path前驱
|
|
|
|
|
int min,i,j,u,pre;
|
|
|
|
|
for(i=0;i<nm.n;i++){
|
|
|
|
|
dist[i]=cont[v1][i];
|
|
|
|
|
s[i]=0;
|
|
|
|
|
if(cont[v1][i]<MAX) path[i]=v1;
|
|
|
|
|
else path[i]=-1;
|
|
|
|
|
}//初始化操作
|
|
|
|
|
s[v1]=1;
|
|
|
|
|
path[v1]=0;
|
|
|
|
|
for(i=0;i<nm.n;i++){
|
|
|
|
|
min=MAX;
|
|
|
|
|
u=-1;
|
|
|
|
|
for(j=0;j<nm.n;j++){
|
|
|
|
|
if(s[j]==0&&dist[j]<min){
|
|
|
|
|
u=j;
|
|
|
|
|
min=dist[j];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(u!=-1){
|
|
|
|
|
s[u]=1;
|
|
|
|
|
for(j=0;j<nm.n;j++)
|
|
|
|
|
if(s[j]==0){
|
|
|
|
|
if(cont[u][j]<MAX&&dist[u]+cont[u][j]<dist[j]){
|
|
|
|
|
dist[j]=dist[u]+cont[u][j];
|
|
|
|
|
path[j]=u;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
printf("智能推荐路线如下(逆序):\n");
|
|
|
|
|
for(i=0;i<nm.n;i++){
|
|
|
|
|
if(i!=v1&&i==v2){
|
|
|
|
|
if(s[i]==1){
|
|
|
|
|
num2=dist[i];
|
|
|
|
|
pre=i;
|
|
|
|
|
while(pre!=v1){
|
|
|
|
|
printf("%s-->",nm.adjust[pre].name);
|
|
|
|
|
money++;
|
|
|
|
|
pre=path[pre];
|
|
|
|
|
}
|
|
|
|
|
printf("%s",nm.adjust[pre].name);
|
|
|
|
|
}
|
|
|
|
|
else printf("路径不存在!");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
printf("\n");
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
##C4:打印菜单,实现功能{231-312}
|
|
|
|
|
```
|
|
|
|
|
代码:int main()
|
|
|
|
|
{
|
|
|
|
|
creatnode();
|
|
|
|
|
createlist();
|
|
|
|
|
//createfile();
|
|
|
|
|
//printff();
|
|
|
|
|
int n=10;
|
|
|
|
|
printf("正在初始化数据,请稍候!\n");
|
|
|
|
|
//proc();
|
|
|
|
|
printf("欢迎使用本系统!\n");
|
|
|
|
|
while(n){
|
|
|
|
|
printf("欢迎来到上海市地铁交通服务平台!\n");
|
|
|
|
|
printf("1.最佳出行线路推荐\n");
|
|
|
|
|
printf("2.出行费用预估\n");
|
|
|
|
|
printf("0.退出系统!\n");
|
|
|
|
|
printf("请输入!\n");
|
|
|
|
|
scanf("%d",&n);
|
|
|
|
|
char str[100];
|
|
|
|
|
int n9,n10;
|
|
|
|
|
switch(n){
|
|
|
|
|
case 1:printf("请输入起点\n");
|
|
|
|
|
scanf("%s",str);
|
|
|
|
|
n9=-1;
|
|
|
|
|
for(int i=0;i<nm.n;i++){
|
|
|
|
|
if(!strcmp(str,nm.adjust[i].name)){
|
|
|
|
|
n9=i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(n9==-1) {
|
|
|
|
|
printf("站点输入错误\n");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
n10=-1;
|
|
|
|
|
printf("请输入终点\n");
|
|
|
|
|
scanf("%s",str);
|
|
|
|
|
for(int i=0;i<nm.n;i++){
|
|
|
|
|
if(!strcmp(str,nm.adjust[i].name)){
|
|
|
|
|
n10=i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(n10==-1) {
|
|
|
|
|
printf("站点输入错误\n");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
Dijkstra(n9,n10);
|
|
|
|
|
case 2:printf("请输入起点\n");
|
|
|
|
|
str[100];
|
|
|
|
|
scanf("%s",str);
|
|
|
|
|
n9=-1;
|
|
|
|
|
for(int i=0;i<nm.n;i++){
|
|
|
|
|
if(!strcmp(str,nm.adjust[i].name)){
|
|
|
|
|
n9=i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(n9==-1) {
|
|
|
|
|
printf("站点输入错误\n");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
n10=-1;
|
|
|
|
|
printf("请输入终点\n");
|
|
|
|
|
scanf("%s",str);
|
|
|
|
|
for(int i=0;i<nm.n;i++){
|
|
|
|
|
if(!strcmp(str,nm.adjust[i].name)){
|
|
|
|
|
n10=i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(n10==-1) {
|
|
|
|
|
printf("站点输入错误\n");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
Dijkstra(n9,n10);
|
|
|
|
|
printf("预估消费%d元\n",money);
|
|
|
|
|
break;
|
|
|
|
|
case 0: return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
##概要设计
|
|
|
|
|
|
|
|
|
|
基于邻接表和邻接矩阵的地铁线路推荐系统,能够根据用户的起点和终点,推荐最佳出行线路,并计算预估消费。
|
|
|
|
|
|
|
|
|
|
##详细设计
|
|
|
|
|
|
|
|
|
|
1.首先定义了几个结构体,包括表示地铁线路的节点(edgenode)、地铁站点(vexnode)和线路列表(list)。然后定义了一个全局变量nm,它是一个线路列表。
|
|
|
|
|
2. createfile()函数是用于创建一个名为"address.txt"的文件,并向其中输入地铁站点的名称。
|
|
|
|
|
3. creatnode()函数是用于初始化地铁站点的数据,它从"address.txt"文件中读取地铁站点的名称,并将这些数据存储在nm.adjust数组中。
|
|
|
|
|
4. printff()函数是用于打印地铁站点的名称。
|
|
|
|
|
5. createlist()函数是用于创建地铁线路的邻接表,描述了每个地铁站点与其相邻站点的关系。
|
|
|
|
|
6. aaa()函数和createjz()函数是用于创建邻接矩阵,描述了地铁站点之间的连接关系。
|
|
|
|
|
7. print()函数是用于打印地铁线路的邻接表。
|
|
|
|
|
8. Dijkstra()函数是用于计算最佳出行线路和预估费用,它使用了Dijkstra算法。
|
|
|
|
|
9. main()函数是程序的入口点,它首先初始化地铁站点的数据,然后进入一个循环,等待用户的输入。用户可以选择最佳出行线路推荐或出行费用预估,或者退出系统。
|
|
|
|
|
|
|
|
|
|
C3:void createjz();
|
|
|
|
|
![C2](images/chuangjian.svg)
|
|
|
|
|
C4:void printf();
|
|
|
|
|
![c3](images/printf.svg)
|
|
|
|
|
C3:void Dijkstra(int v1,int v2);
|
|
|
|
|
![C2](images/suanfa.svg)
|
|
|
|
|
|