1.简介
随着全球化的发展和人们出行需求的日益增长,航空旅行已成为现代生活不可或缺的一部分。为了提高旅客体验,简化预订流程,降低运营成本,航空公司和旅行代理机构迫切需要一个高效、可靠、用户友好的航班订票系统。本项目旨在设计和实现这样一个系统,它能够处理航班信息的查询、票价计算、座位预订、支付处理以及后续的行程管理等功能。
设计目标简述:
- 用户界面友好:系统应提供直观易用的界面,无论是通过网页还是移动应用程序,用户都能轻松进行航班搜索、比较和预订操作。
- 实时数据更新:系统需与航空公司的数据库实时同步,确保显示的航班信息、票价和可用座位数是最新的。
- 多渠道接入:支持多种设备和操作系统,允许用户通过电脑、手机或平板等不同终端进行预订。
- 安全性保障:在处理用户个人信息和支付信息时,系统必须采用加密技术和其他安全措施,保护用户隐私和交易安全。
- 客户服务集成:系统内嵌或链接到客户服务中心,方便用户在遇到问题时快速获得帮助。
- 性能优化:保证在高并发情况下系统仍能稳定运行,减少响应时间,提升用户体验。
- 可扩展性和维护性:设计时应考虑未来可能的功能扩展和技术升级,使系统易于维护和更新。
- 数据分析和报告:系统应具备数据收集和分析功能,帮助航空公司了解市场趋势,优化航班安排和定价策略。
通过实现上述目标,航班订票系统将成为航空公司和旅行代理机构的得力助手,同时也极大地提升了旅客的预订体验,促进了航空业的数字化转型。
2 问题分析
2.1需求描述
在进一步分析航班订票系统的需求时,我们深入探讨了用户、航空公司以及旅行代理机构等各方的需求和期望。以下是对需求的详细描述:
首先,对于用户而言,他们期望系统能够提供方便快捷的航班查询功能,允许他们根据出发地、目的地、出发时间等条件筛选出合适的航班。同时,用户还希望系统能够实时显示各航班的票价、剩余座位数等信息,以便他们做出最优的预订决策。此外,系统还应支持多种支付方式,保障交易的安全和便捷性。最后,用户还期望系统能够提供行程管理的功能,方便他们随时查看和修改自己的订单信息。
对于航空公司而言,他们希望系统能够准确、高效地处理大量的航班信息和预订请求。系统应具备实时更新航班信息的能力,以便航空公司能够及时调整航班计划和票价策略。此外,系统还应提供数据分析和报告的功能,帮助航空公司了解市场趋势、客户需求以及运营状况,从而做出更明智的决策。
对于旅行代理机构而言,他们需要一个能够与航空公司系统对接的、功能强大的航班订票系统,以便为客户提供一站式的旅行预订服务。系统应支持代理机构与航空公司之间的数据同步和交互,确保代理机构能够为客户提供最新、最准确的航班信息,并可以随时调整航班信息。
2.2系统功能描述
在航班订票系统的设计和实现过程中,存储结构的选择至关重要。为了保障数据的高效存储和访问,我们采用了关系型数据库作为主要的存储结构。关系型数据库以其结构化、易于管理和维护的特点,非常适合处理航班信息、用户数据、订单记录等复杂且关联度高的数据。
具体来说,我们定义了以下几个主要的数据库表:
- 航班信息表:用于存储航班的详细信息,包括航班号、出发地、目的地、起飞时间、到达时间、机型、票价等。通过该表,我们可以快速查询和更新航班信息,满足用户对航班查询和预订的需求。
- 可以随时修改相对应的航班信息,包括单独修改单项信息,灵活方便。
- 可以随时删除航班信息,用来应对因环境或不可抗力而取消的航班。
3 数据结构定义
3.1逻辑结构定义
在程序中我使用了线性表的结构,因为在程序中定义的城市,时间,票价等都是有线性关系的数据
数据结构定义:
Passenger 结构体:用于存储航班信息,包括航班号、起飞时间、到达城市、票价、是否满仓和剩余位置。
node 结构体:用于构建链表,每个节点包含一个 Passenger 结构体和指向下一个节点的指针。
功能函数:
menu():显示主菜单,提供用户操作选择。
inputpassenger(node* head):输入新的航班信息并添加到链表尾部。
printpassenger(node* head):遍历链表并打印所有航班信息。
modifypassenger(node* head):根据航班号查找并修改指定航班信息。
findpassenger(node* head):根据航班号查找并显示指定航班信息。
writepassenger(node* head):将链表中的航班信息写入到文件中。
readinfofromfile(node* head):从文件中读取航班信息并构建链表。
delectpassenger(node* head):根据航班号查找并删除指定航班信息。
countpassenger(node* head):统计链表中航班信息的数量。
主函数:
main():程序入口,负责创建链表头节点,读取文件信息,显示菜单,并根据用户选择调用不同的功能。
其他函数:
system("pause") 和 system("cls"):用于暂停程序和清空控制台。
3.2存储结构选择及定义
使用了链式存储
该航班管理系统采用了 单向链表 作为存储结构。
链表的定义:
typedef struct _node
{
Passenger passenger;
struct _node* next;
}node;
链表节点包含两部分:
数据域 : 存储航班信息,包括航班号、起飞时间、到达城市、票价、是否满仓和剩余位置。
指针域 : 指向下一个节点,用于实现链表的链接。
链表的特点:
动态内存分配: 可以根据需要动态地增加或删除节点,灵活地管理航班信息。
插入和删除操作效率高: 只需要修改指针,不需要移动其他元素。
随机访问效率低: 需要从头节点开始遍历链表才能找到特定节点。
使用链表的优势:
代码中,航班信息是动态添加的,使用链表可以方便地管理这些动态数据。
链表可以实现各种操作,例如查找、修改、删除和统计航班信息。
代码中链表的使用:
头结点: 用于指向链表的第一个节点,方便进行操作。
动态内存分配: 使用 malloc 函数为每个节点分配内存。
遍历链表: 使用指针 move 遍历链表,访问每个节点的数据。
插入节点: 将新节点插入到链表的尾部。
删除节点: 删除链表中的特定节点。
释放内存: 使用 free 函数释放链表节点占用的内存。
4 算法设计
4.1算法描述
我负责对代码进行整合与对页面进行设计,我首先使用了main函数将三个新定义函数给整合起来,有打印出来了一个用户页面。
主函数: 创建一个链表头结点,读取航班信息文件,进入主循环,根据用户选择执行不同的功能。
菜单函数: 显示功能菜单,提示用户输入选择。
录入航班信息函数: 创建一个新节点,输入航班信息,并将其添加到链表尾部。
打印航班信息函数: 遍历链表,打印每个节点的航班信息。
查找航班信息函数: 遍历链表,查找并打印指定航班号的航班信息。
修改航班信息函数: 遍历链表,找到指定航班号的航班,根据用户选择修改其信息。
删除航班信息函数: 遍历链表,找到指定航班号的航班,并将其从链表中删除。
统计航班函数: 遍历链表,统计航班总数。
写入航班信息文件函数: 遍历链表,将所有航班信息写入到文件中。
读取航班信息文件函数: 从文件中读取航班信息,并将其添加到链表中。
4.2主要模块及函数设计(伪码描述)
int main() {
node* head = (node*)malloc(sizeof(node));//创建头结点
head->next = NULL;
readinfofromfile(head);
while (1)
{
menu();
char c = getchar();
switch (c)
{
case '0':
printf("录入信息\n");
break;
case '1':
printf("查找信息\n");
break;
case '2':
printf("浏览信息\n");
break;
case '3':
printf("修改信息\n");
break;
case '4':
printf("删除信息\n");
break;
case '5':
printf("剩余位置统计\n");
break;
case '6':
system("cls");
printf("退出成功");
system("pause");
exit(0);
break;
default:
break;
}
system("pause");
system("cls");
}
return 0;
}
void menu()
{
printf("*********************************\n");
printf("*\t 航班管理系统\t\t*\n");
printf("*********************************\n");
printf("*\t 请选择功能\t\t*\n");
printf("*\t 0.录入航班信息\t*\n");
printf("*\t 1.查找航班信息\t*\n");
printf("*\t 2.浏览所有航班\t\t*\n");
printf("*\t 3.修改航班信息\t*\n");
printf("*\t 4.删除航班信息\t*\n");
printf("*\t 5.统计航班\t*\n");
printf("*\t 6.退出系统\t\t*\n ");
printf("*********************************\n");
printf("* 请输入0~6对系统进行操作 *\n");
4.3 主程序的流程以及各个模块之间的调用关系设计
主程序流程:
初始化:
创建头结点 head,指向 NULL。
从文件 stu.info 中读取航班信息,填充链表。
循环执行:
显示菜单,提示用户选择功能。
根据用户输入,调用相应的功能函数:
录入航班信息
查找航班信息
浏览所有航班信息
修改航班信息
删除航班信息
统计航班数量
退出系统
每次执行完功能后,清空控制台,并提示用户继续操作或退出。
退出:
当用户选择 6 时,退出程序。
模块调用关系设计:
主函数 :
调用 menu() 显示菜单。
根据用户选择调用其他功能函数。
功能函数:
inputpassenger(): 录入航班信息,并调用 writepassenger() 保存到文件。
printpassenger(): 浏览所有航班信息。
findpassenger(): 查找航班信息。
modifypassenger(): 修改航班信息,并调用 writepassenger() 保存到文件。
writepassenger(): 将航班信息写入文件。
readinfofromfile(): 从文件读取航班信息到链表。
delectpassenger(): 删除航班信息,并调用 writepassenger() 保存到文件。
countpassenger(): 统计航班数量。
5 算法分析
每次查询都对数据进行遍历,可以减少时间和空间复杂度
由于代码中包含了多个函数,我将分别对每个函数进行算法分析:
1. menu() 函数
功能: 打印菜单选项。
时间复杂度: O(1) - 常数时间,因为只进行了一次打印操作。
空间复杂度: O(1) - 常数空间,因为没有使用额外的存储空间。
2. inputpassenger(node* head) 函数
功能: 录入航班信息。
时间复杂度:
最好情况: O(1) - 如果链表为空,则直接插入新节点。
最坏情况: O(n) - 如果链表很长,需要遍历整个链表才能找到最后一个节点。
平均情况: O(n) - 平均需要遍历链表的一半才能找到插入位置。
空间复杂度: O(1) - 常数空间,因为只分配了一个新节点。
3. printpassenger(node* head) 函数
功能: 浏览所有航班信息。
时间复杂度:
最好情况: O(n) - 需要遍历整个链表才能打印所有信息。
最坏情况: O(n) - 与最好情况相同。
平均情况: O(n) - 与最好情况相同。
空间复杂度: O(1) - 常数空间,因为没有使用额外的存储空间。
4. findpassenger(node* head) 函数
功能: 查找航班信息。
时间复杂度:
最好情况: O(1) - 如果要查找的航班号是链表的第一个节点。
最坏情况: O(n) - 如果要查找的航班号不在链表中,需要遍历整个链表。
平均情况: O(n) - 平均需要遍历链表的一半才能找到目标航班号。
空间复杂度: O(1) - 常数空间,因为没有使用额外的存储空间。
5. modifypassenger(node* head) 函数
功能: 修改航班信息。
时间复杂度:
最好情况: O(1) - 如果要修改的航班号是链表的第一个节点。
最坏情况: O(n) - 如果要修改的航班号不在链表中,需要遍历整个链表。
平均情况: O(n) - 平均需要遍历链表的一半才能找到目标航班号。
空间复杂度: O(1) - 常数空间,因为没有使用额外的存储空间。
6. writepassenger(node* head) 函数
功能: 将航班信息写入文件。
时间复杂度:
最好情况: O(n) - 需要遍历整个链表才能将所有信息写入文件。
最坏情况: O(n) - 与最好情况相同。
平均情况: O(n) - 与最好情况相同。
空间复杂度: O(1) - 常数空间,因为没有使用额外的存储空间。
7. readinfofromfile(node* head) 函数
功能: 从文件读取航班信息。
时间复杂度:
最好情况: O(n) - 需要读取文件中的所有信息才能创建链表。
最坏情况: O(n) - 与最好情况相同。
平均情况: O(n) - 与最好情况相同。
空间复杂度: O(n) - 线性空间,因为需要为每个航班信息分配一个节点。
8. delectpassenger(node* head) 函数
功能: 删除航班信息。
时间复杂度:
最好情况: O(1) - 如果要删除的航班号是链表的第一个节点。
最坏情况: O(n) - 如果要删除的航班号不在链表中,需要遍历整个链表。
平均情况: O(n) - 平均需要遍历链表的一半才能找到目标航班号。
空间复杂度: O(1) - 常数空间,因为没有使用额外的存储空间。
9. countpassenger(node* head) 函数
功能: 统计航班数量。
时间复杂度:
最好情况: O(n) - 需要遍历整个链表才能统计所有航班数量。
最坏情况: O(n) - 与最好情况相同。
平均情况: O(n) - 与最好情况相同。
空间复杂度: O(1) - 常数空间,因为没有使用额外的存储空间。
6 编码实现
使用C语言
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:6031)//消除返回值对scanf的忽略警告
#include<stdio.h>
#include<stdlib.h>
typedef struct _passenger
{
int num;//航班号
char time[20];//起飞时间
char city[20];//到达城市
char price[20];//票价
bool if_full[20];//是否满仓
int remainder;//剩余位置
}Passenger;
typedef struct _node
{
Passenger passenger;
struct _node* next;
}node;
void menu();
void inputpassenger(node* head);
void printpassenger(node* head);
void modifypassenger(node* head);
void findpassenger(node* head);
void writepassenger(node* head);
void readinfofromfile(node* head);
void delectpassenger(node* head);
void countpassenger(node* head);
int main() {
node* head = (node*)malloc(sizeof(node));//创建头结点
head->next = NULL;
readinfofromfile(head);
while (1)
{
menu();
char c = getchar();
switch (c)
{
case '0':
printf("录入信息\n");
inputpassenger(head);
break;
case '1':
printf("查找信息\n");
findpassenger(head);
break;
case '2':
printf("浏览信息\n");
printpassenger(head);
break;
case '3':
printf("修改信息\n");
modifypassenger(head);
break;
case '4':
printf("删除信息\n");
delectpassenger(head);
break;
case '5':
printf("剩余位置统计\n");
countpassenger(head);
break;
case '6':
system("cls");
printf("退出成功");
system("pause");
exit(0);
break;
default:
break;
}
system("pause");
system("cls");
}
return 0;
}
void menu()
{
printf("*********************************\n");
printf("*\t 航班管理系统\t\t*\n");
printf("*********************************\n");
printf("*\t 请选择功能\t\t*\n");
printf("*\t 0.录入航班信息\t*\n");
printf("*\t 1.查找航班信息\t*\n");
printf("*\t 2.浏览所有航班\t\t*\n");
printf("*\t 3.修改航班信息\t*\n");
printf("*\t 4.删除航班信息\t*\n");
printf("*\t 5.统计航班\t*\n");
printf("*\t 6.退出系统\t\t*\n ");
printf("*********************************\n");
printf("* 请输入0~6对系统进行操作 *\n");
}
void inputpassenger(node* head)
{
node* fresh = (node*)malloc(sizeof(node));
if (fresh == NULL) {
printf("分配内存失败");
exit(-1);
}
else
fresh->next = NULL;
printf("请输入航班相关信息\n");
printf("航班号\n");
scanf("%d", &fresh->passenger.num);
printf("时间\n");
scanf("%s", fresh->passenger.time);
printf("城市\n");
scanf("%s", fresh->passenger.city);
printf("票价\n");
scanf("%s", fresh->passenger.price);
printf("是否满仓\n");
scanf("%s", fresh->passenger.if_full);
printf("剩余位置\n");
scanf("%d", &fresh->passenger.remainder);
node* move = head;
while (move->next != NULL)
{
move = move->next;
}
move->next = fresh;
writepassenger(head);
system("pause");//暂停程序
system("cls"); //清空控制台
}
void printpassenger(node* head)
{
node* move = head->next;
while (move != NULL)
{
printf("航班号\t时间\t城市\t票价\t是否满仓\t剩余位置\n");
printf("%d\t%s\t%s\t%s\t%s\t%d\n", move->passenger.num, move->passenger.time, move->passenger.city,
move->passenger.price, move->passenger.if_full, move->passenger.remainder);
move = move->next;
}
system("pause");//暂停程序
system("cls"); //清空控制台
}
void findpassenger(node* head)
{
printf("请输入要查找的航班号");
int num;
scanf("%d", &num);
node* move = head->next;
while (move != NULL)
{
if (num == move->passenger.num)
{
printf("航班号\t时间\t城市\t票价\t是否满仓\t剩余位置\n");
printf("%d\t%s\t%s\t%s\t%s\t%d\n", move->passenger.num, move->passenger.time, move->passenger.city,
move->passenger.price, move->passenger.if_full, move->passenger.remainder);
system("pause");//暂停程序
system("cls"); //清空控制台
}
move = move->next;
}
printf("未找到航班信息");
system("pause");//暂停程序
system("cls"); //清空控制台
}
void modifypassenger(node* head)
{
printf("请输入需要修改的航班号\n");
int num;
scanf("%d", &num);
node* move = head->next;
while (move != NULL)
{
if (move->passenger.num == num)
{
int number;
printf("请输入0~5分别代表航班号、时间、城市、票价、是否满仓、剩余位置\n");
scanf("%d",&number);
switch (number)
{
case 0:
printf("修改航班号\n");
printf("请输入需要修改后的航班号\n");
scanf("%d", &move->passenger.num);
writepassenger(head);
printf("修改成功\n");
system("pause");//暂停程序
system("cls"); //清空控制台
break;
case 1:
printf("修改到达时间\n");
printf("请输入需要修改后的时间\n");
scanf("%s", &move->passenger.time);
writepassenger(head);
printf("修改成功\n");
system("pause");//暂停程序
system("cls"); //清空控制台
break;
case 2:
printf("修改到达城市\n");
printf("请输入需要修改后的城市\n");
scanf("%s", &move->passenger.city);
writepassenger(head);
printf("修改成功\n");
system("pause");//暂停程序
system("cls"); //清空控制台
break;
case 3:
printf("修改票价\n");
printf("请输入需要修改后的票价\n");
scanf("%s", &move->passenger.price);
writepassenger(head);
printf("修改成功\n");
system("pause");//暂停程序
system("cls"); //清空控制台
break;
case 4:
printf("修改是否满仓\n");
printf("请输入需要修改后的是否满仓\n");
scanf("%s", &move->passenger.if_full);
writepassenger(head);
printf("修改成功\n");
system("pause");//暂停程序
system("cls"); //清空控制台
break;
case 5:
printf("修改剩余位置\n");
printf("请输入需要修改后的剩余位置\n");
scanf("%d", &move->passenger.remainder);
writepassenger(head);
printf("修改成功\n");
system("pause");//暂停程序
system("cls"); //清空控制台
break;
default:
break;
}
return;
}
move = move->next;
}
printf("未找到航班信息\n");
system("pause");//暂停程序
system("cls"); //清空控制台
}
void writepassenger(node* head)
{
FILE* file = fopen("./stu.info", "w");
if (file == NULL) {
printf("打开文件失败\n");
return;
}
node* move = head->next;
while (move != NULL)
{
if (fwrite(&move->passenger, sizeof(Passenger), 1, file) != 1) {
printf("写入失败\n");
return;
}
move = move->next;
}
fclose(file);
printf("数据保存成功\n");
}
void readinfofromfile(node* head)
{
FILE* file = fopen("./stu.info", "r");
if (!file) {
printf("没有航班文件,跳过读取\n");
return;
}
node* fresh = (node*)malloc(sizeof(node));
if (fresh == NULL) { //取消对NULL指针fresh的引用警告
exit(-1);
}
else
fresh->next = NULL;
node* move = head;
while (fread(&fresh->passenger, sizeof(Passenger), 1, file) == 1)
{
if (move->next != NULL) {
move->next = fresh;
}
move = fresh;
node* fresh = (node*)malloc(sizeof(node));
if (fresh == NULL) {
printf("分配内存失败");
exit(-1);
}
else
fresh->next = NULL;
}
free(fresh);
fclose(file);
printf("读取成功\n");
}
void delectpassenger(node* head)
{
printf("请输入需要删除航班的航班号");
int num;
scanf("%d", &num);
node* move = head;
while (move->next != NULL)
{
if (move->next->passenger.num == num)
{
node* temp = move->next;
move->next = move->next->next;
free(temp);
temp = NULL;
writepassenger(head);
printf("删除成功");
system("pause");//暂停程序
system("cls"); //清空控制台
}
else {
printf("未找到航班信息");
system("pause");//暂停程序
system("cls"); //清空控制台
}
move = move->next;
}
}
void countpassenger(node* head)
{
int count = 0;
node* move = head->next;
while (move != NULL)
{
count++;
move = move->next;
}
printf("总的航班数%d\n", count);
system("pause");
system("cls");
}
7 调试、测试与运行记录
在航班管理系统的开发过程中,调试、测试与运行记录是确保系统稳定、可靠的关键环节。本部分将详细记录调试过程中遇到的问题、测试的方法和结果,以及运行记录的要点。
调试过程:
在调试阶段,我们主要关注以下几个方面:
-内存管理:检查是否存在内存泄漏、野指针等问题。通过编译器和内存检测工具,确保每个分配的内存块都有正确的释放操作。
-函数接口:验证各个函数之间的参数传递是否正确,返回值是否符合预期。特别关注文件读写函数,确保数据能够正确加载和保存。
-逻辑错误:通过逐步跟踪程序执行流程,检查逻辑判断是否出错
8 总结
通过本次航班管理系统的设计与实现,我们深入了解了如何使用C语言进行数据处理和文件操作。系统实现了航班信息的录入、查找、浏览、修改、删除以及统计功能,满足了用户的基本需求。在开发过程中,我们注重代码的可读性和可维护性,采用了模块化的设计思想,使得每个功能都能独立运行和测试。同时,我们也对系统进行了充分的调试和测试,确保其在各种情况下都能稳定运行。