2需求分析
2.1系统功能
1、 客运订票系统的功能描述
每条车次所涉及的信息有:起点站名、终点站名、车次ID、列车号、出发日期(星期几)、乘员定额、剩余票数、票价、已经订票的客户名单(包括姓名、订票量)以及等候替补的客户名单(包括姓名、所需票量)。
2、通过此订票系统可以实现如下功能:
①查询车次:根据客户提供的终点站名进行查询,可以输出以下信息:车次号、列车号、星期几出发和余票量等。也可以根据车次号,查询列车某个车次的情况;
②订票:根据客户提出的要求(姓名、终点站名、订票数量)查询该车次的余票量情况。如尚有足够的余票,则为客户办理订票手续;若已满员或余票量少于订票数量,则需要重新询问客户要求,如需要,可登记排队候补;
③退票:根据客户提供的情况(姓名、终点站名、出发日期、列车号),为客户办理退票手续,然后查询该车次是否有人排队候补,首先询问排在第一的客户,若所退的票额能满足他的要求,则为他办理订票手续,否则依次询问其他排队候补的客户;
④管理员对车次信息进行增、删、改、查操作:可以录入车次、删除车次、查询车次的功能,但是只限于管理员操作。
3总体设计
3.1功能模块图
本客运订票系统分为五个功能模块,分别是车次搜索查询模块、订票模块、退票模块、管理员模块。查询搜索模块可以进行显示当前车次功能、搜索车次信息:订票模块可以对用户的需求来进行订相当于的机票功能:退票模块可以对用户的需求来进行退票功能:管理员功能可以通过登陆管理员账号来进行增加、删除、查找和更改车次车次信息。功能模块图如图3-1所示。
4详细设计
4.1 详细的设计思路
车次设置:
每条车次所设计的信息有:车次ID、起点站名、终点站名、列车号、出发时间(星期几)、成员定额、总余票量、二等座余票量、一等座余票量、已订票的客户名单、二等座候补客户名单、一等座候补客户名单。其中,二等座候补客户名单和一等座候补客户名单中的包括以下几个域:姓名、身份证、所需票量、预定票的等级
车次搜索查询模块的功能
1.搜索所有车次的相关信息
2.根据起点和终点查询车次
3.返回上一级菜单
订票模块的功能:
1.输入车次ID进行订票,当车次ID不存在或者不合法时要求重新输入车次ID,然后输入订票数量和等级,数量和等级要合法,订票数目要大于0,等级输入1代表二等座,输入其他数据一等座。不合法则重新输入,再判断对应等级的票是否足够 ,足够则继续输入客户信息(姓名和身份证),然后订票成功。当对应等级的票数不足时,询问是否改变订票计划,同意改变计划则重新输入车次ID进行相应的订票操作。不同意改变计划则继续询问是否排队等候,不同意排队等候则询问是否需要推荐相同车次的其他车次,询问操作时,输入Y或者y表示同意,输入N,n或者其它数据表示不同意。
2.根据起点和终点查询车次
3.查询所有车次的相关信息
4.查询车次的订票情况,输入车次ID,当车次ID不存在或者不合法时要求重新输入车次ID,根据ID查询车次,显示出已订票的客户的姓名、订票数目和仓位等级,为了保密,不能显示客户的身份证。
5.返回上一级菜单
退票模块的功能:
1.先输入车次ID,然后输入姓名和身份证号码进行验证,验证成功则办理退票手续。然后查询该车次是否有人排队候补,如果有,而且票数够了,则首先询问排在第一的客户,是否需要订票,是则为他办理订票手续,否则出队,依次询问其他排队候补的客户。若刚刚退票的是二等座,则询问二等座排队的客户;若是一等座,则询问一等座排队的客户。
2.返回上一级菜单
管理员模块的功能:
1.管理员账号密码验证
2.查询所有车次信息
3.根据车次ID查询客户信息(包括身份证号码)
4.增加车次(车次的各个信息输入要合法,不合法的重新输入)
5.删除车次,根据ID进行删除,ID不存在则删除失败。
6.返回上一级菜单
4.2 算法流程图
5编码
5.1数据结构定义
1.乘客信息
使用结构体存储客户订票信息(客户姓名、订票量、身份证号码、座位等级)
typedef struct CustomerNode {
char name[10];//客户姓名
int clientTickets;//客户订票量
char identification[20];//客户身份证号码
int rank;//座位等级
CustomerNode *next;
} CustomerNode, *CusLinkList;
2. 候补队列乘客信息
typedef struct WaitPassenger {
char name[10];//姓名
char identification[20]; //身份证
int preTickets;//预定的票量
struct WaitPassenger *next;
} WaitQNode, *PWait;
3.候补票队列
typedef struct Queue {
PWait front;//等候替补客户名单域的头指针
PWait rear;//等候替补客户名单域的尾指针
} LinkQueue;
4.乘客信息
typedef struct NameAndNumAndID {
char name[10];//姓名
char identification[20]; //身份证号码
int num;//订票量
} NameAndNumAndID;
5.车次信息:
使用结构体定义车次的起点站名,终点站名,车次ID,列车号,出发日期,乘员定额,总余票量,二等座剩余量,一等座剩余量等信息。
typedef struct TrainNumber{
char startPoint[20];//起点站名
char destination[20];//终点站名
char TrainNumberCodeID[20];//车次ID
char planeNum[20];//列车号
char day[20];//出发(星期几)
int totalTickets;//乘员定额(总票数)
int left;//总余票量
int leftEconomicTicket; //二等座剩余量
int leftBusinessTicket; //一等座剩余量
TrainNumber*next;
CusLinkList cusLinkList;//乘员名单域,指向乘员名单链表的头指针
LinkQueue waitQueue1;// 二等座候补,等候替补的客户名单域,指向一个队列
LinkQueue waitQueue2;// 一等座候补,等候替补的客户名单域,指向一个队列
} TrainNumber, TrainNumberNode, *PTrainNumber;
5.2功能函数设计
(1)功能函数 MenuSelect
函数的功能:主菜单界面函数,对车次搜索查询模块,订票模块,退票模块,管理员模块,退出模块进行选择调用。
函数的入口:AdministratorFace,Suggest,SearchFace,BookticketFace,ReturnTicketsFace,main函数。
函数调用关系:被AdministratorFace,MenuSelect,Suggest,SearchFace,BookticketFace,ReturnTicketsFace,main函数调用。调用了system,SearchFace, MenuSelect,BookticketFace,ReturnTicketsFace,AdministratorVerify,AdministratorFace,GoodbyeFace函数。
函数的出口:调用完相对应的功能函数后break结束。
(2)功能函数 BookticketFace;
函数的功能:订票模块菜单界面。对客户订票,根据起点和终点查询车次,查询所有车次,通过ID查询订票客户名单进行选择调用。
函数的入口:MenuSelect函数
函数调用关系:被MenuSelect,BookticketFace调用。调用了BookTickets,BookticketFace,SearchTrainNumber,PrintTrainNumberlist,PriCusInfo,system,MenuSelect函数。
函数的出口:调用完相对应的功能函数后break结束。
(3)功能函数 BookTickets
函数的功能:实现订票功能。
函数的入口:Suggest,BookticketFace函数。
函数调用关系:被BookTickets,Suggest,BookticketFace函数调用,调用了system,FlightInfo,BookTickets函数。
函数的出口:输入Y/N和y/n。
(4)功能函数 ReturnTicketsFace
函数的功能: 退票模块菜单界面。
函数的入口:MenuSelect函数
函数调用关系:被MenuSelect函数调用,调用了ReturnTicketsFace, ReturnTicket,MenuSelect函数。
函数的出口:调用完相对应的功能函数后break结束。
(5)功能函数 ReturnTicket
函数的功能: 实现退票功能。
函数的入口:ReturnTicketsFace函数
函数调用关系:只被ReturnTicketsFace函数调用,调用了strcmp函数
函数的出口:调用完相对应的功能函数后break结束。
(6)功能函数 AdministratorFace
函数的功能:管理员界面函数
函数的入口:MenuSelect函数
函数调用关系:只被MenuSelect函数调用。调用了PrintTrainNumberlist,AdministratorFace,AdminPriCusInfo,InsertTrainNumber,DeleteTrainNumber,MenuSelect函数
函数的出口:调用完相对应的功能函数后break结束。
(7)功能函数 AdministratorVerify
函数的功能:验证管理员账号和密码。
函数的入口:MenuSelect函数。
函数调用关系:只被MenuSelect函数调用,只调用strcmp函数。
函数的出口:验证成功返回1。
5.3函数流程图
(1) 主菜单界面函数流程图如图5-1所示。
图5-1
(2) 订票模块菜单界面函数流程图如图5-2所示。
图5-2
(3) 订票模块函数流程图如图5-3所示。
图5-3
(4) 退票模块菜单界面函数流程图如图5-4所示。
图 5-4
(5) 退票功能函数流程图如图5-5所示。
图 5-5
(6) 管理员界面函数流程图如图5-6所示。
图 5-6
(7) 管理员账号验证函数流程图如图5-7所示。
图5-7
5.4 程序实现
主菜单界面函数
//主菜单界面函数
//@return 返回选择的操作
int MenuSelect() {
int select;
Status status;
flag:
{
system("cls");
printf("\n 19级软件工程xxxx xxxxxxxxxxxx\n");
printf(" 指导老师:xxx \n\n\n");
printf(" 欢迎来到客运订票系统\n");
printf(" -----------------------------------------------------\n");
printf(" | 1. 车次搜索查询模块 |\n");
printf(" | 2. 订票模块 |\n");
printf(" | 3. 退票模块 |\n");
printf(" | 4. 管理员模块 |\n");
printf(" | 5. 离开系统 |\n");
printf(" -----------------------------------------------------\n");
printf(" 请输入您的选择:");
scanf("%d", &select);
}
switch (select) {
case 1:
//查询所有车次信息
//进入搜索模块
//传入车次链表头指针,打印出所有车次信息
SearchFace();
MenuSelect();
break;
case 2:
//进入订票模块
BookticketFace();
system("PAUSE");
MenuSelect();
break;
case 3:
//进入退票模块
ReturnTicketsFace();
system("PAUSE");
MenuSelect();
break;
case 4:
//进入管理员模块
while (1) {
status = AdministratorVerify();
if (1 == status)
break;
}
AdministratorFace();
system("PAUSE");
MenuSelect();
break;
case 5:
//退出模块
GoodbyeFace();
break;
default:
goto flag;
}
}
(2)订票模块菜单界面函数。
//订票界面
//属于订票模块
void BookticketFace() {
int a3;
int loop3;
loop3:
{
system("cls");
printf("\n\n ");
printf(" 订票模块\n");
printf(" ------------------------------------------------------------------\n");
printf(" | 1.客户订票 |\n");
printf(" | 2.根据起点和终点搜索车次 |\n");
printf(" | 3.查询所有车次 |\n");
printf(" | 4.通过车次ID查询订票客户名单 |\n");
printf(" | 5.返回上一级菜单 |\n");
printf(" -----------------------------------------------------------------\n");
printf(" 请输入您的选择:");
scanf("%d", &a3);
}
switch (a3) {
case 1:
//订票
BookTickets();
system("PAUSE");
BookticketFace();
break;
case 2:
//输入起点和终点查询
SearchTrainNumber();
system("PAUSE");
BookticketFace();
break;
case 3:
PrintTrainNumberlist(pTrainNumber);
system("PAUSE");
BookticketFace();
break;
case 4:
//为了保密,只能查到客户的姓名和订票量,查不到身份证
PriCusInfo();
system("PAUSE");
BookticketFace();
break;
case 5:
MenuSelect();
break;
default:
goto loop3;
}
}
(3)订票功能函数
//订票模块
void BookTickets() {
struct TrainNumber *info;
int amount, rank;
int tickets;//剩余的一等座数目或者二等座数目
char name[10];
char identification[20];
system("cls");
//调用查找车次函数,返回给
int loop1;
loop1:
{
info = find();
};
if (info == NULL){
printf("没有这个车次, 请重新输入\n");
goto loop1;
}
int loop2;
loop2:
{ printf("请正确输入你订票所需要的数量:");
scanf("%d", &amount);
};
//非法字符,重新输入
if (amount <= 0 ) {
goto loop2;
}
printf("请正确输入您的票的座位等级(1代表二等座,2或其他代表一等座):");
scanf("%d", &rank);
if (rank == 1)
tickets = info->leftEconomicTicket;
else
tickets = info->leftBusinessTicket;
if (amount <= tickets) {
int i;
printf("请输入您的姓名:");
scanf("%s", name);
printf("请输入您的身份证号码:");
scanf("%s", identification);
CusLinkList head = info->cusLinkList;
//订票成功,插入成员名单链表
insertlink(head, amount, name, identification, rank);
for (i = 0; i < amount; i++)
printf("%s 的座位号是: %d\n", name, info->totalTickets - info->left + i + 1);
info->left -= amount;
if (rank == 1)
info->leftEconomicTicket -= amount;
else
info->leftBusinessTicket -= amount;
printf("\n祝您旅途愉快!欢迎再次光临\n");
} else
loop0:
{
char r;
printf("该等级的票不足,订票失败,以下为该车次乘客信息,希望对您的订票有所帮助\n");
FlightInfo(info);
printf("是否改变订票计划?Y/N\n");
r = getch();
printf("%c", r);
if (r == 'Y' || r == 'y') {//改变计划,重新选择车次
BookTickets();
} else {
printf("\n已经没有更多的票,您需要排队等候吗?(Y/N)");
r = getch();
printf("%c", r);
if (r == 'Y' || r == 'y') {//不改变计划,排队候票
printf("\n请输入您的姓名(排队订票客户):");
scanf("%s", name);
printf("\n请输入您的身份证号码(排队订票客户):");
scanf("%s", identification);
if (rank == 1) {//进入二等座排队队列
info->waitQueue1=Appendqueue(info->waitQueue1,name, amount, identification);
} else {//进入一等座排队队列
info->waitQueue2=Appendqueue(info->waitQueue2,name, amount, identification);
}
printf("\n排队成功!\n");
} else {//不排队,选择系统提供的其他建议方案
printf("\n是否根据建议订票?若是,则推荐相同的起点和终点的车次Y/N");
r = getch();
printf("%c", r);
printf("%c", r);
if (r == 'Y' || r == 'y') {
//调用推荐函数
Suggest(info->startPoint, info->destination, info);
} else
printf("\n欢迎您下次再次订购!\n");
}
}
}
}
(4)退票模块菜单界面函数
//退票模块界面
void ReturnTicketsFace() {
int a3;
int loop4;
loop4:
{
system("cls");
printf("\n\n ");
printf(" 退票模块\n");
printf(" --------------------------------------------------------\n");
printf(" | 1.办理退票手续 |\n");
printf(" | 2.返回上一级菜单 |\n");
printf(" --------------------------------------------------------\n");
printf(" 请输入您的选择:");
scanf("%d", &a3);
}
switch (a3) {
case 1:
ReturnTicket();
system("PAUSE");
ReturnTicketsFace();
break;
case 2:
MenuSelect();
break;
default:
goto loop4;
}
}
(5)退票功能函数
//退票功能函数
void ReturnTicket() {
struct TrainNumber *info;
int rank;
//p1为遍历指针,p2为辅助指针,指向p1的前驱
CustomerNode *p1, *p2, *head;
//客户姓名
char cusname[10];
//客户身份证
char identification[20];
system("cls");
//info指针,find函数根据车次ID返回该车次节点的指针
int loop;
loop:
{
info = find();
};
if (info == NULL){
printf("没有这个车次, 请重新输入\n");
goto loop;
}
//head为该车次的的乘员名单域的头指针
head = info->cusLinkList;
//带头结点的指针,head->next 开始遍历
p1 = head->next;
printf("请输入你的姓名: ");
scanf("%s", cusname);
printf("请输入你的身份证号码: ");
scanf("%s", identification);
//根据客户姓名搜索客户是否订票
p2 = head;
while (p1 != NULL) {
if ((strcmp(cusname, p1->name) == 0) && (strcmp(identification, p1->identification) == 0)) break;
p2 = p1;
p1 = p1->next;
}
if (p1 == NULL) {
printf("对不起,你没有订过票或姓名和身份证不对应\n");
return;
} else {//退票成功
//从乘客名单域中移除该节点
rank = p1->rank;
p2->next = p1->next;
//加回该车次的剩余票
info->left += p1->clientTickets;
if (rank == 1) {
info->leftEconomicTicket += p1->clientTickets;
} else {
info->leftBusinessTicket += p1->clientTickets;
}
printf("%s 成功退票!\n", p1->name);
free(p1);
}
LinkQueue queue1 = info->waitQueue1;
LinkQueue queue2 = info->waitQueue2;
NameAndNumAndID nameAndNumAndID = {0, 0};
if (rank == 1) { //有二等座退票,询问二等座排队的客户
for (; queue1.front->next != NULL && queue1.front->next->preTickets <= info->leftEconomicTicket;) {
//从候补客户队列中,出队客户的姓名和订票量用NameAndNumAndID返回
QueueDelete(info->waitQueue1, nameAndNumAndID);
int y;
printf("有 二等座票 剩余 , 尊敬的%s :\n", nameAndNumAndID.name);
printf("是否确认订票(1确认订票, 其他数字拒绝订票\n");
scanf("%d", &y);
if (y == 1) {
//排队订票成功
for (int i = 0; i < nameAndNumAndID.num; i++)
printf("排队订票成功 %s 的座位号是:%d\n", nameAndNumAndID.name, (info->left) - i);
//剩余票减少
info->left -= nameAndNumAndID.num;
info->leftEconomicTicket -= nameAndNumAndID.num;
//乘员名单链表插入排队订票成功的客户
info->cusLinkList = insertlink(info->cusLinkList, nameAndNumAndID.num, nameAndNumAndID.name,
nameAndNumAndID.identification, rank);
}
}
} else { //有一等座客户退票,询问一等座排队的客户
for (; queue2.front->next != NULL && queue2.front->next->preTickets <= info->leftBusinessTicket;) {
//从候补客户队列中,出队客户的姓名和订票量用NameAndNumAndID返回
QueueDelete(info->waitQueue2, nameAndNumAndID);
int y;
printf("有 一等座票 剩余 , 尊敬的%s :\n", nameAndNumAndID.name);
printf("是否确认订票(1确认订票, 其他数字拒绝订票\n");
scanf("%d", &y);
if (y == 1) {
//排队订票成功
for (int i = 0; i < nameAndNumAndID.num; i++)
printf("排队订票成功%s 的座位号是:%d\n", nameAndNumAndID.name, (info->left) - i);
//剩余票减少
info->left -= nameAndNumAndID.num;
info->leftBusinessTicket -= nameAndNumAndID.num;
//乘员名单链表插入排队订票成功的客户
info->cusLinkList=insertlink(info->cusLinkList,nameAndNumAndID.num, nameAndNumAndID.name, nameAndNumAndID.identification, rank);
}
}
}
}
(6)管理员模块界面函数
// 管理员模块
//管理员界面函数
void AdministratorFace() {
int a2;
int loop2;//goto语句
loop2:
{
system("cls");
printf("\n\n \n \n ");
printf(" 欢迎进入管理系统 \n");
printf(" -----------------------------------------------------\n");
printf(" | 1.车次信息 |\n");
printf(" | 2.客户信息 |\n");
printf(" | 3.增加车次 |\n");
printf(" | 4.删除车次 |\n");
printf(" | 5.返回上一级 |\n");
printf(" -----------------------------------------------------\n");
printf(" 请输入您的选择:");
scanf("%d", &a2);
}
switch (a2) {
case 1:
PrintTrainNumberlist(pTrainNumber);
system("PAUSE");
AdministratorFace();
break;
case 2:
AdminPriCusInfo();
AdministratorFace();
case 3:
InsertTrainNumber();
AdministratorFace();
break;
case 4:
if (1 == DeleteTrainNumber()) {
printf("删除成功\n");
} else {printf("没有这个车次,删除失败!\n");
};
AdministratorFace();
case 5:
MenuSelect();
break;
default:
goto loop2;
}
}
(7)管理员账号验证函数
//验证管理员账号密码
//@return 返回操作结果
Status AdministratorVerify() {
char pwd[20] = "123456";//管理员密码
char ID[20]="admin" ;//管理员ID
char id[20];
char password[20];//待输入密码,用来验证
printf("请输入管理员账号:\n");
scanf("%s",id);
if (strcmp(ID, id)) {
printf("账号错误,请重新输入:\n");
return -1;
}
printf("请输入管理员密码:\n");
scanf("%s", password);
if (strcmp(pwd, password)) {
printf("密码错误,请重新输入:\n");
return -1;
}
printf("验证成功\n");
return 1;
}