前言:这个是帮别人写的,过了一年了,也不记得啥了,应该是个挺简单的小系统。想着也期末考了,报告和代码分享给大家。发这些报告,是觉得对我也没什么用了,不如拿出来对大家有所帮助,也希望能收获一些点赞和关注(*^_^*)
本人原创,不希望被商用
目 录
企业员工出差查询系统
一、需求分析
1.问题描述
年末企业会派员工出差去各城市分公司盘点库存。企业员工从北京出发,需要去10~12个城市进行盘点。本系统是帮助企业员工查询所有分公司所在城市信息,帮助企业员工选择从北京到各分公司的最短路径和最短距离的系统。查询所有分公司所在城市信息采用图的深度优先搜索和广度优先搜索算法,最短路径采用迪杰斯特拉算法。具体要求如下:
(1)自行选定10~12个分公司所在城市(必须包含北京),通过百度查询各个城市之间的真实距离,假设每个城市均有直达火车。按照中国地图布局画出10~12个分公司分布简图。
(2)使用图的综合知识实现分公司分布图的深度优先搜索遍历,输出各分公司信息。
(3)使用图的综合知识实现分公司分布图的广度优先搜索遍历,输出各分公司信息。
(4)利用迪杰斯特拉算法输出北京到任意分公司之间的最短距离和路径。
(5)自行设计一个功能,解决系统的一个实际问题。
2.基本要求
1.要求1(10分):分公司数量符合要求,分公司和分公司之间的距离以邻接矩阵形式存储正确画出公司分布图简图
2.要求2(30分):实现分公司分布图的深度优先搜索遍历,实现分公司分布图的广度优先搜索遍历,正确讲解算法
3.要求3(20分):利用迪杰斯特拉算法输出北京到任意分公司之间的最短距离和路径
4.要求4(5分),正确描述自行设计的功能,采用相应算法实现该功能
5.要求5(15分):功能全部实现
6.要求6(20分):内容能充分体现程序开发过程
3.逻辑结构和存储结构的选择
4测试数据
1.使用图像编译软件绘制了按照中国地图布局画出的分公司分布简图。如下:
二、概要设计
1.抽象数据类型
以下是一些用到的数据类型
const int MM=20;//设置常量
const int N=0xfffff;//设置最大值
//一些全局变量
struct FGS
{
int num;//分公司代码
char chenshi[100];//所在城市名字
}fgs[MM]={{},{1,"北京"},{2,"济南"},{3,"上海"},{4,"福州"},{5,"郑州"},{6,"长沙"},{7,"西安"},{8,"兰州"},{9,"成都"},{10,"重庆"},{11,"贵阳"}};//初始化
//结构体存储分公司编号和所在城市
int lj[MM][MM]=
{
{N,N,N,N,N,N,N,N,N,N,N,N},
{N,0,626,1206,N,692,N,1071,1467,N,N,N},
{N,626,0,813,N,446,1180,N,N,N,N,N},
{N,1206,813,0,764,N,1045,N,N,N,N,N},
{N,N,N,764,0,N,850,N,N,N,N,1539},
{N,692,446,N,N,0,803,482,N,N,N,N},
{N,N,1180,1045,850,803,0,983,N,N,891,776},
{N,1071,N,N,N,482,983,0,626,N,N,N},
{N,1467,N,N,N,N,N,626,0,866,976,N},
{N,N,N,N,N,N,N,N,866,0,301,631},
{N,N,N,N,N,N,891,N,976,301,0,N},
{N,N,N,N,1539,N,776,N,N,631,N,0},
};//邻接矩阵存储城市距离
int hc[MM][MM]=
{
{N,N,N,N,N,N,N,N,N,N,N,N},
{N,0,170,600,N,350,N,555,700,N,N,N},
{N,170,0,400,N,200,550,N,N,N,N,N},
{N,600,400,0,375,N,500,N,N,N,N,N},
{N,N,N,375,N,0,425,N,N,N,N,750},
{N,350,200,N,N,0,400,250,N,N,N,N},
{N,N,550,500,425,400,0,500,N,N,450,400},
{N,555,N,N,N,250,500,0,300,N,N,N},
{N,700,N,N,N,N,N,300,0,425,500,N},
{N,N,N,N,N,N,N,N,425,0,150,325},
{N,N,N,N,N,N,450,N,500,150,0,N},
{N,N,N,N,750,N,400,N,N,325,N,0},
};//邻接矩阵存储地图火车费用
2.系统功能图
(1)菜单功能 |
(2)深度优先搜索功能 |
(3)广度优先搜索功能 |
(4)查询单条最短路径功能 |
(5)查询所有最短路径功能 |
(6)查询单个火车费用功能 |
(7)查询所有火车费用功能 |
(8)关闭功能 |
三、详细设计
1.算法的详细设计
以下是源代码+注释文件:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h>
#include <queue>
#include <stack>
//一些头文件
using namespace std;
const int MM=20;//设置常量
const int N=0xfffff;//设置最大值
//一些全局变量
struct FGS
{
int num;//分公司代码
char chenshi[100];//所在城市名字
}fgs[MM]={{},{1,"北京"},{2,"济南"},{3,"上海"},{4,"福州"},{5,"郑州"},{6,"长沙"},{7,"西安"},{8,"兰州"},{9,"成都"},{10,"重庆"},{11,"贵阳"}};//初始化
//结构体存储分公司编号和所在城市
int lj[MM][MM]=
{
{N,N,N,N,N,N,N,N,N,N,N,N},
{N,0,626,1206,N,692,N,1071,1467,N,N,N},
{N,626,0,813,N,446,1180,N,N,N,N,N},
{N,1206,813,0,764,N,1045,N,N,N,N,N},
{N,N,N,764,0,N,850,N,N,N,N,1539},
{N,692,446,N,N,0,803,482,N,N,N,N},
{N,N,1180,1045,850,803,0,983,N,N,891,776},
{N,1071,N,N,N,482,983,0,626,N,N,N},
{N,1467,N,N,N,N,N,626,0,866,976,N},
{N,N,N,N,N,N,N,N,866,0,301,631},
{N,N,N,N,N,N,891,N,976,301,0,N},
{N,N,N,N,1539,N,776,N,N,631,N,0},
};//邻接矩阵存储城市距离
int hc[MM][MM]=
{
{N,N,N,N,N,N,N,N,N,N,N,N},
{N,0,170,600,N,350,N,555,700,N,N,N},
{N,170,0,400,N,200,550,N,N,N,N,N},
{N,600,400,0,375,N,500,N,N,N,N,N},
{N,N,N,375,N,0,425,N,N,N,N,750},
{N,350,200,N,N,0,400,250,N,N,N,N},
{N,N,550,500,425,400,0,500,N,N,450,400},
{N,555,N,N,N,250,500,0,300,N,N,N},
{N,700,N,N,N,N,N,300,0,425,500,N},
{N,N,N,N,N,N,N,N,425,0,150,325},
{N,N,N,N,N,N,450,N,500,150,0,N},
{N,N,N,N,750,N,400,N,N,325,N,0},
};//邻接矩阵存储地图火车费用
bool vs[MM];//存储判断点位,在dij和搜索中用到
int path[MM];//存储中转结点,在dij中用到
int d[MM];//存储最短权值,在dij中用到
void H(); //欢迎界面
void M(); //主菜单界面
void A(); //深搜界面
void dfs(int); //深搜算法
void B(); //广搜界面
void bfs(); //广搜算法
void C(); //最短路界面
void dij(int); //dij算法
void print(int); //用栈输出最短路
void D(); //最小费用界面
void dij2(int);//dij算法2
void print2(int); //用栈输出经过站点
int main() //主函数
{
H();//欢迎界面
M();//主菜单界面
return 0;
}
void A()
{
printf("正在从1号总公司开始深度优先搜索!\n\n");
memset(vs,false,sizeof(vs));
dfs(1);
}
void dfs(int u)
{
printf("dfs:%d号公司在%s\n",fgs[u].num,fgs[u].chenshi);
vs[u] = 1;
for(int i=1;i<=11;i++)
{
if(lj[u][i] && !vs[i])
{
dfs(i);
}
}
}
void B()
{
printf("正在从1号总公司开始广度优先搜索!\n\n");
memset(vs,false,sizeof(vs));
bfs();
}
void bfs()
{
queue<int>q;
q.push(1);
vs[1]=1;
while(q.size()>0)
{
int u = q.front();
q.pop();
printf("bfs:%d号公司在%s\n",fgs[u].num,fgs[u].chenshi);
for(int i=1;i<=11; i++)
{
if((hc[u][i]!=0&&hc[u][i]!=N)&&!vs[i])
{
q.push(i);
vs[i]=1;
}
}
}
}
void C()
{
memset(vs,false,sizeof(vs));
memset(path,-1,sizeof(path));
dij(1);
int x;
printf("查询单个路径还是所有路径?(0/1)");
scanf("%d",&x);
if(x==0)
{
printf("请输入前往的分公司编号:(2-11):\n");
scanf("%d",&x);
print(x);
}
else
{
print(1);
}
}
void dij(int sec) //sec为出发节点
{
int i,j,min,min_num;
int vis[MM]={0,};
for(i=1;i<=11;i++)
{
d[i]=lj[sec][i];
}
vis[sec]=1;d[sec]=0;
for(i=1;i<=11;i++)
{
min=N;
for(j=0;j<11;j++)
{
if(!vis[j]&&d[j]<min)
{
min=d[j];
min_num=j;
}
}
vis[min_num]=1;
for(j=1;j<=12;j++)
{
if(d[j]>min+lj[min_num][j])
{
path[j]=min_num;//path[j]记录d[j]暂时最短路径的最后一个中途节点min_num,表明d[j]最后一段从节点min_num到节点j
d[j]=min+lj[min_num][j];
}
}
}
}
void print(int sec) //sec为出发节点,n表示图中节点总数
{
int i,j;
stack<int> q; //由于记录的中途节点是倒序的,所以使用栈(先进后出),获得正序
if(sec==1)
{
for(i=2;i<=11;i++) //打印从出发节点到各节点的最短距离和经过的路径
{
j=i;
while(path[j]!=-1) //如果j有中途节点
{
q.push(j); //将j压入堆
j=path[j]; //将j的前个中途节点赋给j
}
q.push(j);
printf("%d号总公司到%d号分公司的最短距离为%d, 具体路径为%d ",1,i,d[i],1);
while(!q.empty()) //先进后出,获得正序
{
printf("%d ",q.top());//打印堆的头节点
q.pop(); //将堆的头节点弹出
}
printf("\n");
}
}
else
{
j=sec;
while(path[j]!=-1) //如果j有中途节点
{
q.push(j); //将j压入堆
j=path[j]; //将j的前个中途节点赋给j
}
q.push(j);
printf("%d号总公司到%d号分公司的最短距离为%d, 具体路径为%d ",1,sec,d[sec],1);
while(!q.empty()) //先进后出,获得正序
{
printf("%d ",q.top());//打印堆的头节点
q.pop(); //将堆的头节点弹出
}
printf("\n");
}
}
void D()
{
memset(path,-1,sizeof(path));
dij2(1);
int x;
printf("查询单次出差费用还是所有出差费用?(0/1)");
scanf("%d",&x);
if(x==0)
{
printf("请输入本次出差前往的分公司编号:(2-11):\n");
scanf("%d",&x);
print2(x);
}
else
{
print2(1);
}
}
void dij2(int sec) //sec为出发节点
{
int i,j,min,min_num;
int vis[MM]={0,};
for(i=1;i<=11;i++)
{
d[i]=hc[sec][i];
}
vis[sec]=1;
d[sec]=0;
for(i=1;i<=11;i++)
{
min=N;
for(j=0;j<11;j++)
{
if(!vis[j]&&d[j]<min)
{
min=d[j];
min_num=j;
}
}
vis[min_num]=1;
for(j=1;j<=12;j++)
{
if(d[j]>min+hc[min_num][j])
{
path[j]=min_num;//path[j]记录d[j]暂时最短路径的最后一个中途节点min_num,表明d[j]最后一段从节点min_num到节点j
d[j]=min+hc[min_num][j];
}
}
}
}
void print2(int sec) //sec为出发节点,n表示图中节点总数
{
int i,j;
stack<int> q; //由于记录的中途节点是倒序的,所以使用栈(先进后出),获得正序
if(sec==1)
{
for(i=2;i<=11;i++) //打印从出发节点到各节点的最短距离和经过的路径
{
j=i;
while(path[j]!=-1) //如果j有中途节点
{
q.push(j); //将j压入堆
j=path[j]; //将j的前个中途节点赋给j
}
q.push(j);
printf("%d号总公司到%d号分公司所需火车票费用为%d元, 具体需购买以下站点票:\n%s ",1,i,d[i],fgs[1].chenshi);
while(!q.empty()) //先进后出,获得正序
{
printf("->%s ",fgs[q.top()].chenshi);//打印堆的头节点
q.pop(); //将堆的头节点弹出
}
printf("\n");
}
}
else
{
j=sec;
while(path[j]!=-1) //如果j有中途节点
{
q.push(j); //将j压入堆
j=path[j]; //将j的前个中途节点赋给j
}
q.push(j);
printf("%d号总公司到%d号分公司所需火车票费用为%d元, 具体需经过以下城市站点:\n%s ",1,sec,d[sec],fgs[1].chenshi);
while(!q.empty()) //先进后出,获得正序
{
printf("->%s ",fgs[q.top()].chenshi);//打印堆的头节点
q.pop(); //将堆的头节点弹出
}
printf("\n");
}
}
//页面显示
void H()
{
printf("欢迎进入企业员工出差查询系统!\n\n");
printf("\t\t |--------------------------|\n");
printf("\t\t |-- 企业员工出差查询系统 --|\n");
printf("\t\t |--------------------------|\n");
printf("\n");
return;
}
void M()
{
int I=0;//用来判断选择操作
while (1)//循环结构,保证在输入错误或结束一个操作之后可以再次出现操作页面
{
printf("\t\t=================================\n");
printf("\t\t 1.分公司信息(深搜)\n");
printf("\t\t 2.分公司信息(广搜)\n");
printf("\t\t 3.查询最短路径\n");
printf("\t\t 4.查询最低交通费用\n");
printf("\t\t 5.退出管理系统\n");
printf("\t\t=================================\n");
printf("\t\t请输入相应功能前的数字进行操作:\n");
scanf("%d", &I);//输入操作序号
switch (I)//通过分支选择判断语句,选取函数执行
{
case 1:
A();
break;
case 2:
B();
break;
case 3:
C();
break;
case 4:
D();
break;
case 5:
exit(0);//意为正常状态退出,该程序停止执行
default:
printf("选择错误,请重试!\n");//如果输出不符合要求,该循环结构会重新执行
}
}
}
2.函数间的调用关系
函数 | 内容 | 嵌套,调用 |
void H(); | 欢迎界面 | |
void M(); | 主菜单界面 | A(),B(),C(),D() |
void A(); | 深搜界面 | Dfs() |
void dfs(int); | 深搜算法 | Dfs() |
void B(); | 广搜界面 | Bfs() |
void bfs(); | 广搜算法 | |
void C(); | 最短路界面 | Print(),dij() |
void dij(int); | dij算法 | |
void print(int); | 用栈输出最短路 | |
void D(); | 最小费用界面 | Dij2(),print2() |
void dij2(int); | dij算法2 | |
void print2(int); | 用栈输出经过站点 | |
int main() | 主函数 |
四、调试分析
1.程序运行截图
(1)菜单功能
(2)深度优先搜索功能
(3)广度优先搜索功能
- 查询单条最短路径功能
- 查询所有最短路径功能
- 查询单个火车费用功能
- 查询所有火车费用功能
(8)关闭功能
2.程序中函数时间复杂度
函数 | 时间复杂度 |
void H(); | O(1) |
void M(); | ~ |
void A(); | O(1) |
void dfs(int); | O(N^2) |
void B(); | O(1) |
void bfs(); | O(N^2) |
void C(); | O(1) |
void dij(int); | O(N^2) |
void print(int); | O(N^2) |
void D(); | O(1) |
void dij2(int); | O(N^2) |
void print2(int); | O(N^2) |
int main() | O(1) |
五、总结
经过努力,完成了数据结构课程设计的期末报告。在这个过程中,为了完成这个企业员工出差查询系统,我具体分析了题目的问题描述和基本要求运用到了本学期所学的图论以及最短路、深度优先搜索,广度优先搜索,迪杰斯特拉算法等知识点,并运用到了部分关于栈,队列的知识。体会到了程序设计的开发过程是怎样子的。
为了制作出一个较为完整的企业员工出差查询系统,我逐个从点击破,通过函数分装的方式将各个功能需求分装书写,以达到让城市更简洁易懂的目的。在制作过程中遇到了一些问题:
对深度优先搜索以及广度优先搜索的便利差别在哪?
迪杰斯特拉如何标记路径达到输出的目的?
自行设计功能应该运用到哪些知识点?
对此,我结合教材以及互联网上的资料进行了深度学习,从中学习到对该系统更有用处的处理方式。然后我通过实践运用多次更改代码,将代码改成更符合要求的程序。
本次课程设计综合总结了该学期的数据结构,让我能够将理论应用于实际,学到了更多知识。