数据结构课程设计航空订票系统+拯救007问题.docx
《数据结构课程设计航空订票系统+拯救007问题.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计航空订票系统+拯救007问题.docx(25页珍藏版)》请在冰豆网上搜索。
数据结构课程设计航空订票系统+拯救007问题
《数据结构》
课程设计报告
姓名:
XXXXX班号:
XXXX
学号:
XXXXXXXX专业:
XXXXX
院(系):
XXXXXXX指导教师:
XXXX
2014年1月
一题:
航空订票系统
1.需求分析
试设计一个航空订票系统,基本要求如下:
每条航班所涉及的信息有:
航班号,航班机型,起飞机场,降落机场,日期(星期几),起飞时间,降落时间,飞行时长,价格(三种价位),乘员定额,余票量(三种舱位的票量),订定票的客户名单(包括姓名,订票量,舱位等级(头等舱、公务舱、经济仓),飞机票座位号以及等候替补的客户名单(包括姓名、所需机票数量以及舱位等级)。
采用链式存储结构。
系统能实现的操作和功能如下:
(1)航班信息管理(航班增加和删除)。
(2)查询航线,按以下几种方式查询:
①按航班号查询;
②按起点站查询;
③按终点站查询;
④按日期查询;
每种查询方式中,查询后输出如下信息:
航班号,航班机型,起飞机场,降落机场,日期(星期几),起飞时间,降落时间,飞行时长,价格,余票量。
(3)承办订票业务:
根据客户提出的要求(航班号,订票数额)查询该航班票额情况,若有余票,则为客户办理订票手续,输出座位号;若已满员或余票少于订票额,则需重新询问客户要求。
若需要,可登记排队候补(加入询问顾客是否接受余票少于订票量时购买)。
(4)承办退票业务:
根据客户提出的情况(日期,航班号),为客户办理退票手续,然后查询该航班是否有人排队候补,首先询问排在第一的客户,若所退票额能满足他的要求,则为他办理订票手续,否则依次询问其它排队候补的客户。
2.设计
2.1设计思想
(1)数据结构设计
逻辑结构设计是采用线性表逻辑结构,存储结构设计是采用链表存储结构。
原因分析:
对于航班采用链式存储,便于对航班机进行动态增加、删除和查找。
对于每个航班结构体内部,除了设置必要的如航班号、航班机型等元素外,还必须创建已经买票的顾客链表头结点(存放已经购票的顾客信息)、等待买票的顾客头结点(存放排队买票的顾客信息)、三种舱位的位子号头结点(存放剩余的舱位座号,用指针连接)。
同时在已经买票的顾客结构体内部还必须建立所买票的座位号结构体头结点(存放该顾客飞机票的座位号)。
(2)算法设计
1模块划分及主要功能:
航空订票系统总共分为5个主功能模块,其中查询航班又分为了4个次一级的功能模块。
a.添加航班模块:
增加航班,此时函数通过每个舱位的票量生成座位号的链表并且链入航班的结构体里面。
b.删除航班模块:
根据要求删除航班链表中的航班,并且释放掉买票顾客链表,等待顾客链表和三条座位号链表。
c.查询航班模块:
根据要求显示所查询的航班信息。
d.订票模块:
根据顾客的要求进行订票,当票数不足是询问顾客是否购买;当票数为0时询问顾客是否进入等待队列,买好票的顾客进入顾客队列并且链入座位号链表
e.退票模块:
根据顾客要求退票,然后将余票和等待的顾客要求进行比较,满足则讲票卖给等待的顾客,并将顾客链入已买票的顾客链表。
f.查票模块:
顾客输入姓名查看自己的买票或者等待信息。
2主程序流程图:
③主要算法思想:
航空订票系统中最主要的还是链表的综合操作,包括结点空间的申请链入、结点的动态增加和删除等等。
算法思想就是创建各个链表的结点指针,通过指针进行查找、删除、增加和修改。
2.2设计表示
(1)函数调用关系图
(2)函数接口规格说明
Flight*head;//全局变量
//函数规格
voidmenu();//航空订票系统功能菜单
voidListInitiate(Flight**);//对航班头指针head的初始化函数
voidStartAir();//在程序内部存储一组航班的函数
voidBookTicket();//订票系统函数
voidReturnTicket();//退票系统函数
voidAddAirline();//增加航班线路函数
voidDeleteAieline();//删除航班线路函数
voidSearchTicket();//查询订票情况函数
voidSearchAirline();//航空线路查询函数
voidSearchMenu();//查询功能菜单函数
voidNumSearch();//按航班号查询函数
voidStartPlaceSearch();//按起点站查询函数
voidEndPlaceSearch();//按终点站查询函数
voidDateSearch();//按日期查询函数
2.3详细设计
(1)元素结构体
航班元素结构体:
包含航班号、航班机型、起飞机场、降落机场日期(星期几)、起飞
时间、降落时间、飞行时长、价格、乘员定额、余票量以及订票、
等待和座位号的头指针。
订票顾客结构体:
包含订票人姓名、订票数量、舱位等级以及所买票座位号头指针。
排队顾客结构体:
包含等待人姓名、等待的数量和舱位等级、是否接受票数少于订票
数量的标志位。
座位号结构体:
包含了座位号。
(2)主要功能函数伪代码
①voidBookTicket()//订票系统函数
{
输入订票的日期;
if(找到航班)输出航班信息
else提示航班不存在,做出选择
else
{
输入要订票的航班号、订票的数目、舱位等级
根据航班号和日期唯一确定航班,进入订票
根据舱位等级操作其对应的余票量
if(余票量为0)
询问是否进入等待买票队列
如果等待,输入姓名以及是否接受票数小于订票量时购买
进入等待买票排队
if(余票足够)
输入买票人姓名,根据票数在座位号链表里截取等数量的座位结点
成功订票输出座位号,并将其链入顾客结点
买票人信息进入买票顾客链表
if(余票少于买票量)
提示票量不足,是否购买
如果购买,则重新输入票数,进行购买
买票人信息进入买票顾客链表
}
②voidReturnTicket()//退票系统函数
{
输入退票人姓名、航班号、日期、舱位等级
通过航班号+日期唯一确定一个航班
if(未找到该航班)则输出未找到该航班
if(找到该航班)
{
由姓名找到该航班里的这个顾客信息
if(找到这个顾客)
{
将该顾客的座位链表按照升序插入到相应舱位的航班座位链表里面
修改相应舱位的飞机余票量
删除该顾客结点。
输出退票成功
查找该航班该舱位等级的等待顾客链表,从首元素结点开始比较票数
在等待买票的顾客链表不空或者余票不为0的情况下
if(余票数大于订票数)
对该等待各科进行补票,并链入座位链表
将该顾客从等待队列删除,链入买票顾客的链表尾部
修改余票,继续往后比较等待顾客的票数
if(余票数小于订票数)
if(等待顾客接受余票少于订票时订票)
将票全卖给等待的人,并创建新的买票顾客结点,写入信息并且链上座位
号,将结点链入买票顾客链表
修改等待买票顾客订票数的结点,结束
else
继续往后比较等待顾客的票数
}}}
③voidSearchTicket()//查询订票情况函数
{
输入姓名进行查找
从链表的第一个结点开始访问其买票和等待顾客链表
在买票链表里找到姓名则输出买票的航班信息以及座位号
在等待的链表里找到则输出还未买票、等待的舱位等级和票量
否则输出未找到订票信息
}
3.调试分析
(1)调试过程中遇到的问题:
对于买票后座位号的输出一开始用公式计算,所以导致在
几个人买完票后,如果1号票退票,但是后面的人是买不
到1号票的。
解决方法:
设置座位号的链表,买票结束后就将其座位号结点从总链表上截下链
入顾客结点,退票的时候将座位结点按照升序规则插入总链表。
编码的回顾与讨论分析:
航空订票系统总共有1500行左右的代码,但是实际上有
很多重复的代码,造成这个现象的原因是,一开始按照题目要求进行系统设计,但是在课设验收过程中不断的根据老师的要求从结构体开始改进,添加更多细化的功能函数(比如说座位号功能的实现、舱位等级的区分)等等,导致在修改代码的过程中造成代码的多余。
(2)算法的时间空间复杂度分析:
航空订票系统的空间复杂度分析最终是归结于其存存储结构—单链表。
增加和删除
的时间复杂度是O(n),其余的时间复杂度是O
(1)。
空间复杂度都为O
(1)。
4.用户手册
航班信息中航班号、价格、余票都是int型数据,输入时注意只能输入数字;
机票定额是指每种舱位的票量,而不是三种舱位总共的票数;
航空订票系统中航班可以由航班号和日期唯一确定;
程序中预先存储了一个航班,为了操作更加合理,可以事先进行航班的添加,在添加的过程中必须注意不同的航班其航班号和日期不能同时相同,这和实际情况是不符合的。
5.测试数据及测试结果
程序中存储的航班信息为:
航班号
机型
起飞机场
降落机场
日期
起飞时间
降落时间
飞行时长
1
K101
wuhan
beijing
Mon
7:
00
10:
00
3:
00
价格(头等舱/公务舱/经济舱)
定额
余票(头等舱/公务舱/经济舱)
15010050
30
303030
输入的增加航班是:
航班号
机型
起飞机场
降落机场
日期
起飞时间
降落时间
飞行时长
2
K202
nanjing
wuhan
Sun
15:
00
16:
30
1:
30
价格(头等舱/公务舱/经济舱)
定额
余票(头等舱/公务舱/经济舱)
1007045
50
505050
航班号
机型
起飞机场
降落机场
日期
起飞时间
降落时间
飞行时长
1
K303
shanghai
beijing
Wen
00:
00
1:
30
1:
30
价格(头等舱/公务舱/经济舱)
定额
余票(头等舱/公务舱/经济舱)
200150130
80
808080
数据测试:
Ø主功能菜单
Ø程序中存储的航班信息查询
Ø航班信息的增加
Ø航班的删除
Ø订票和排队买票
Ø退票和重新买票时座位号的变换
Ø退票和补票成功时的查询
6.源程序清单
本次程序是把程序写到一个CPP文件里面了,所以我把几个结构体和重要的函数展示一下
typedefstructCLI
{
charcustomers[10];//订票顾客姓名
intBookTicketsNum;//订票数量
structSEA*seater;//座位号指针
intlevel;//订票等级
structCLI*next1;
}Client;//订票顾客结构体
typedefstructSUB
{
charwaiters[10];//等待订票顾客姓名
intNeedTickets;//定票量
intlevel;//
structSEA*seater;//座位号指针
intsign;//标志位,判断顾客是否接受在票数不足的情况下订票
structSUB*next2;
}Substitute;//等待订票顾客结构体
typedefstructSEA
{
intseat;
structSEA*next;
}ZuoWeiHao;
typedefstructNode
{
intNum;//航班号
charAirModel[8];//航班机型
charStartPlace[20];//起飞机场
charEndPlace[20];//降落机场
charDate[10];//日期
charStartTime[10];//起飞时间
charEndTime[10];//降落时间
charNeedTime[10];//飞行时长
intprice1;//1等舱价格
intprice2;//2等舱价格
intprice3;//3等舱价格
intorder;//乘员定额
intRemain1;//1等舱余票量
intRemain2;//2等舱余票量
intRemain3;//3等舱余票量
structCLI*customer;//订票顾客头指针
structSUB*waiter;//等待顾客头指针
structSEA*seater1;//头等舱座位号指针
structSEA*seater2;//公务舱座位号指针
structSEA*seater3;//经济舱座位号指针
structNode*next;//下一班航班指针
}Flight;
voidmenu();//航空订票系统功能菜单
voidListInitiate(Flight**);//对航班头指针head的初始化函数
voidStartAir();//在程序内部存储一组航班的函数
voidBookTicket();//订票系统函数
voidReturnTicket();//退票系统函数
voidAddAirline();//增加航班线路函数
voidDeleteAieline();//删除航班线路函数
voidSearchTicket();//查询订票情况函数
voidSearchAirline();//航空线路查询函数
voidSearchMenu();//查询功能菜单函数
voidNumSearch();//按航班号查询函数
voidStartPlaceSearch();//按起点站查询函数
voidEndPlaceSearch();//按终点站查询函数
voidDateSearch();//按日期查询函数
三题:
最短路径,拯救007
1.需求分析
看过007系列电影的人们一定很熟悉JamesBond这个著名的特工。
在电影”LiveandLetDie”中JamesBond被一组毒品贩子捉住并且关到湖中心的一个小岛上,而湖中有很多凶猛的鳄鱼。
这时JamesBond做出了最惊心动魄的事情来逃脱——他跳到了最近的鳄鱼的头上,在鳄鱼还没有反应过来的时候,他又跳到了另一只鳄鱼的头上……最后他终于安全地跳到了湖岸上。
假设湖是100×100的正方形,设湖的中心在(0,0),湖的东北角的坐标是(50,50)。
湖中心的圆形小岛的圆心在(0,0),直径是15。
一些凶残的鳄鱼分布在湖中不同的位置。
现已知湖中鳄鱼的位置(坐标)和JamesBond可以跳的最大距离,请你告诉JamesBond一条最短的到达湖边的路径。
他逃出去的路径的长度等于他跳的次数。
要求:
(1)输入要求:
程序从文件中读取输入信息,文件中包括的多组输入数据。
每组输入数据包括鳄鱼的数量、007可以跳的最大距离、鳄鱼的坐标(没有两只鳄鱼出现在同一个位置)。
(2)输出要求:
程序结果输出到文件中。
对于每组输入数据,如果007可以逃脱,则输出007必须跳的最小的步数,然后按照跳出顺序记录跳出路径上的鳄鱼坐标;如果007不能逃脱,则输出-1到文件。
2.设计
2.1设计思想
(1)数据结构设计
逻辑结构设计是采用队列对图进行广度搜索的逻辑结构,存储结构设计是采用队列存储结构。
原因分析:
在拯救007的问题中,可以简化成寻寻找路径的问题,007能否跳到鳄鱼头上再跳到下一鳄鱼头上,最终跳到岸上,即寻找结点来构建边,使小岛(007所处的位置)与岸上连通,让实际问题成为抽象的几何问题,通过判断再建立边这样就形成图通过搜索算法就可以找出路径来了。
(2)算法设计
①总体设计思路
a.建立点模块:
鳄鱼所处的位置即各个点,泥潭中有多少鳄鱼就有多少个点,根据鳄鱼所处的位置建立点即可。
b.边建立模块:
由上面的点已经建立,根据题目我们得之,建立的边既是007能跳到鳄鱼的头上,那么只要007能直接跳到某鳄鱼头上(或岸上)都要建立边。
c.图的搜索模块:
通过搜索建立的图可以找出可以实现的路径。
d.路径打印模块:
通过寻找出来的路径一次打印出007的运动状态(经过的点)。
3主要算法思想:
拯救007问题主要过程:
程序从“input.txt”文件中读取输入信息,这个文件包含了多组输入据。
每组输入数据的起始行中包含了两个整数n和d,n是鳄鱼的数量而且n<=100,d是007可以跳的最大距离而且d>0。
起始行下面的每一行是鳄鱼的坐标(x,y),其中x,y都是整数,而且没有任何两只鳄鱼出现在同一位置。
Input.txt文件以一个负数结尾。
输出要求:
程序结果输出到output.txt文件中。
对于每组输入数据,如果007可以逃脱,则输出到output.txt文件的内容格式如下:
第一行是007必须跳的最小步数,然后按照跳出顺序记录跳出路径上的鳄鱼坐标(x,y),每行一个坐标。
如果007不可能跳出去,则将-1写入文件。
如果这里有很多个最短路径,只需输入其中的任意一种。
2.2设计表示
(1)函数调用关系图
(2)函数接口规格说明
GraphGraphNew(intNodeNum)//创建新的图
DequeDequeNew()//创建队列
intCheckForStart(intx,inty,Distanced)//判断能否从岛上跳到鳄鱼头上
intCheckForEnd(intx,inty,Distanced)//判断从鳄鱼头上跳到岸上
intCheckForConnect(Graphg,Vertexi,Vertexj,Distanced)//判断能否从鳄鱼i跳到鳄鱼j点的头上
voidError(constchar*msg)//检测是否打印错误
Graphread_case(FILE*InFile,intnum,Vertex*Bank,DequeD)//记录最短到达河岸的路径
voidwrite_result(FILE*OutFile,VertexBank,GraphG,DequeD)//打印最短路径
voidDequeClear(DequeD)//队列的删除
2.3详细设计
为了记录007跳过的路径,可定义为如下结构:
typedefunsignedintVertez;
typedefdoubleDistance;
typedefstructGraphNodeRecord{
intx;//x轴坐标
inty;//y轴坐标
unsignedintStep;
VertexPath;//跳到本节点之间007所在节点
}GraphNode;
typedefGraphNode*Grapha;
寻找跳出路径的算法:
读出一组测试数据返回007跳过的路径Graph,记录最短到达湖岸的路径。
该算法实际上是应用队列对图进行广度搜索,以寻找到岸边的最短路径,其中入队列与出队列函数分别是Inject()和Pop()*/
Graphread_case(FILE*InFile,intnum,Vertex*Bank,DequeD)
{
GraphG=NULL;
DistanceJ;
VertexV;
intx,y;
inti,Times;
*Bank=0;//初始化跳出的路径的记录
fscanf(Infile,”%lf”,&J);//读取步长
if(007能直接跳到岸上)
{
*Bank=1;//直接跳出的情况
}
elseif(007必须经过鳄鱼头上)
{
num+=2;
G=GraphNew”(num);
for(i=2;i{
if(007能从岛上跳上该点)
{
G[i].Path=1;
G[i].Step=1;
if(007能从该点是否能跳出)
{
*Bank=i;//可以跳出,记录该点
Skipothercrocodile
break;
}
else
Inject(i,D);//插入该点,并开始下一个检测
}
}
while(只经过一只鳄鱼无法跳出,必须还要跳到其他鳄鱼)
{
V=Pop(D);
for(i=2;i{
if(bondcanjumpfromvtoi,andstepofi>stepofv+1)
{
G[i].Path=V;
G[i].Step=G[V].Step+1;//把i点练到v点后面
if(bondcanjumpfromitobankandthepathisshorterthanothers)
*Bank=i;
else
Inject(i,D);
}
}
}
}
returnG;
}
在执行完算法read_case后,*Bank值可能如下3种可能:
(1)k,返回的第k点是007经过最短路径逃出鳄鱼潭是经过的最后一个顶点。
;
(2)1,意味着007可以直接从岛上跳出去,而不用经过鳄鱼的脑袋;
(3)0,意味着007无法逃脱出去
可以根据G[k]的path参数来追踪该点的上一点,由此类推可以得到007逃脱的最短路径。
3.调试分析
(1)拯救007问题的难点有这么几点,1、用队列还是用堆栈。
2、如何建立图,建立这些些图的条件是是什么。
3、图的搜索,关乎到有向图还是无向图。
编码的回顾与讨论分析:
首先就是如何建立队列,建立的方面有点和边两个需要建立,开始的没有思路,后来找到同学王益明帮忙,通过他的帮助,我渐渐的分析解决的去掉这个问题,但是如和建立边,边的建立相对比较简单,通过判断能否跳出,能则连通,不能则没有变。
第一个问题,开始的时候想用数组但是后来发现数组越操作越麻烦,虽然看起来比较简单,但是没有用队列那种逻辑关联性好。
第三个问题,开始我是按照有向图建立的图,但是我没有注意到后来的时候由于相互连接的问题使得图表成了无向图。
这次编程对图的了解更加深刻了。
(2)算法的时间空间复杂度分析:
空间复杂度:
主要是体现在图的储存和路径的记录上面。
在图的存储上面是有信息和后面连接的几个点所以复杂度是O(n),而后面的路径的存储则是记录几点,及与路径经过的状态是相同的,所以空间复杂度是O
(1)。
时间复杂度:
时间最主要的是用在了建立点建立边,建立点的时候经过for语句的嵌套然后实现这样时间复杂度为O(n^4).但是好在每一次的判断只有2种情况。
后面在建立变的时候是对文件中的各个点经行了嵌套搜索,所以复杂度为O(n^2).
4.用户手册
本次的程序是这运行出现结果的无需操作。
只需要在最后的时