数据结构:火车售票系统(C语言)
问题描述
该系统可支持售票、退票及剩余车票状态查询等功能。每张车票包含的信息包括列车运行时刻、车厢号别以及座位类型等。
问题要求
如购票、退票以及查询余额等操作流程中,则须确保系统能够清晰展示出相关的车次信息。具体而言,在购票时系统会自动核验乘客身份并记录乘车人信息;退票操作则会完整记录每一笔交易的详细信息;而查询余额的操作则会生成一份完整的订单详情单,并列出每一笔交易的基本数据及金额信息。
⑵为简单起见,在此假设所有出售的车票均为同一车次的车票。
当需要退票时,仅限于车站已经开具的车票方能办理退款;若非如此,则视为无效,并无法退还该车票;此外,在办理完退款后仍可继续销售该车票
一、解题思路
1、总体思路
该系统主要围绕车票售出、退票以及剩余票数查询等功能进行设计。为实现高效管理目标,在程序运行过程中首先构建包含乘客信息、座位号及票价等字段的结构体,并利用数组存储这些数据。售票模块能够根据当前系统状态接受有效订单,并动态地更新数据库中的售出记录。当用户发起退款请求时会先验证用户身份信息及订单编号的有效性,在确认无误后执行相应的退款操作。为了便于用户直观了解当前状态主界面包含多个功能选项按钮对应不同功能操作如购票查询可退票价范围设置 etc。这些功能相互关联形成一个完整的操作流程框架从而实现了系统的整体管理需求
2、各函数思路
售票函数sellTicket():
首先检查车票是否售罄。
通知用户录入车厢号和座位号信息,并对订单的有效性进行验证,请特别注意检查该订单是否已成功售出。
当成功时,请生成一个车票结构体,并将其加入到车票库数组中;同时将已售车票的数量进行更新,并输出售票成功的相关信息。
退票函数refundTicket():
接收用户输入的要退票的车次、车厢和座位信息并进行有效性检查。
遍历整个数据库中的票务信息列表,并对每个订单进行字符串对比以及其他相关信息的数据匹配操作,以便完成退票流程。
当系统检测到有符合条件的车票存在时,在确保乘客权益的前提下执行替换单位后将对应车次的已售座位数减少相应的数值,并生成退票成功提示信息。当系统无法匹配到乘客所持有的有效证件类型或发班时间时,则会发送相应提示并要求重新选择车次。
查询剩余票函数queryRemain():
创建一个表示座位是否为空的二维数组。
遍历已售车票,标记已售出的座位。
然后按车厢输出未被标记(即剩余)的座位号。
3、主函数
main():
提供一个循环,让用户不断选择操作(售票、退票、查余票、退出)。
根据用户选择调用相应函数。
二、代码
1、头文件
typedef struct
{
char trainNumber[10]; //车次
int coach; //车厢
int seat; //座号
}Ticket;
2、售票函数 sellTicket
int ticketCount = 0; //初始化已售车票数量为0
void sellTicket()
{
Ticket ticket; // 声明一个Ticket类型的局部变量以存储新票的信息
printf("Please enter coach (1-3):\n");
scanf("%d", &ticket.coach);
printf("Please enter seat (1-8):\n");
scanf("%d", &ticket.seat);
// 检查输入是否有效
if (ticket.coach < 1 || ticket.coach > 3 || ticket.seat < 1 || ticket.seat > 8)
{
printf("Input error, please re-enter!\n");
return;
}
// 检查是否已经售出相同的票
int found = 0;
strcpy(ticket.trainNumber, "G1234");
for (int i = 0; i < ticketCount; i++)
{
if (strcmp(tickets[i].trainNumber, ticket.trainNumber) == 0 &&
tickets[i].coach == ticket.coach &&
tickets[i].seat == ticket.seat)
{
printf("Already sold!\n");
found = 1;
break;
}
}
if (found)
{
return; // 如果已经售出,则直接返回,不添加新票
}
// 检查票是否已售完
if (ticketCount >= 3 * 8)
{
printf("The tickets are sold out!\n");
return;
}
tickets[ticketCount++] = ticket;
printf("Ticketing successful!\n");
printf("Here is the ticket information:\n");
printf("Train number:%s\n", ticket.trainNumber);
printf("coach:%d\n", ticket.coach);
printf("Seating:%d\n", ticket.seat);
printf("\n");
}
注意:
这段代码采用了 strcpy 函数。其作用是将字符串 "G1234" 赋值给 ticket 对象的 trainNumber 成员字段中。
这表明该系统将指定的'G1234'字符串分配给ticket对象的carriageCode属性,并因此确定了这张车票的具体列车信息。
在运行 tickets[ticketCount++] = ticket; 这条指令时,在线将新增的车票信息(由变量 ticket 指示)存储到 tickets 数组中的其索引位置基于当前已售出的车票数量(由变量 ticketCount 给出)。
假设最初 ticketCount 被设定为 0,则系统会将第一条售出的票务信息存储在数组中的第一个索引位置即 tickets[0] 。当再售出一张时, ticketCount 增加至1, 系统会将新的信息则会被存储在数组中的第二个索引位置即 tickets[1] 。依此类推, 每当有新票务被卖出时, 都会按顺序将新生成的信息依次放入对应索引位置上, 这使得已处理过的票务记录能够持续有序地存在于数组中。
3、退票函数 refundTicket
void refundTicket()
{
char trainNumber[10];
int coach, seat;
printf("Please enter the train number to be refunded:\n");
scanf("%s", trainNumber);
printf("Please enter the coach (1-3) to be refunded:\n");
scanf("%d", &coach);
printf("Please enter the seat to be refunded (1-8):\n");
scanf("%d", &seat);
if (coach < 1 || coach > 3 || seat < 1 || seat > 8)
{
printf("Input error, please re-enter!\n");
return;
}
for(int i = 0;i < ticketCount;i++)
{
if(strcmp(tickets[i].trainNumber,trainNumber) == 0)
{
tickets[i] = tickets[ticketCount - 1];
ticketCount--;
printf("Ticket refund successful! Here is the ticket information:\n");
printf("train number:%s\n", tickets[i].trainNumber);
printf("coach:%d\n", tickets[i].coach);
printf("seat:%d\n", tickets[i].seat);
return;
}
}
printf("Invalid ticket, cannot be refunded:\n");
printf("\n");
}
注意 :
tickets[i] = tickets[ticketCount - 1];这里是将前一个卖出的车票信息分配至当前退票位置。这种操作本质上是从后往前复制最后一条卖出的记录至指定位置,并从逻辑上表示该位置的数据已被删除。
ticketCount--;:这是在对已售出车票的数量进行降值操作,在编程语境中等同于将变量值减小1个单位。具体来说,在这里表示已售出车票的数量减少了1张。这种变化直接反映了由于刚刚完成了一次退票操作而导致的实际销售量发生了相应调整。在程序逻辑中,“ticketCount--;”这一语句执行后,“已售出车票的数量”这一指标会被更新为最新的数值,并影响后续所有依赖于该变量的操作行为
4、查询剩余函数 queryRemain
void queryRemain()
{
printf("G1234 Remaining seats on the train:\n");
int emptySeats[3][8] = {0}; //记录座位状态
int i, j;
for (i = 0; i < ticketCount; i++)//遍历车票数组
{
if (strcmp(tickets[i].trainNumber, "G1234") == 0)
{
emptySeats[tickets[i].coach - 1][tickets[i].seat - 1] = 1;
}
}
for (i = 0; i < 3; i++)
{
printf("coach %d:", i + 1);
for (j = 0; j < 8; j++)
{
if (emptySeats[i][j] == 0)
{
printf("number%d ", j + 1);
}
}
printf("\n");
}
}
注意 :
strcmp() 函数用于比较两个字符串。
该程序逐一比对两个字符串的所有字符内容,并根据其顺序关系进行判断。当两个数据完全一致时,返回零;若第一个序列在顺序上低于第二个序列,则输出负数值;反之亦然,在这种情况下则输出正数值。
在上述代码中,利用 strcmp(tickets[i].trainNumber, "G1234") 用于识别当前票务信息属于哪一列车(编号'G1234')的信息,并从而完成对应座位的状态标记。
5、主函数 main
int main()
{
int choice;
while(1)
{
printf("****************Welcome to the Train Ticketing System***************\n");
printf("\n 1.sellTicket\n");
printf("\n 2.refundTicket\n");
printf("\n 3.queryRemain\n");
printf("\n 4.exit\n");
printf("\n*********************************************************************\n");
printf("\nPlease select a choice!\n");
scanf("%d",&choice);
switch(choice)
{
case 1:
sellTicket();
break;
case 2:
refundTicket();
break;
case 3:
queryRemain();
break;
case 4:
exit(0);
break;
default:
printf("Invalid ticket, cannot be refunded£¡\n");
}
}
return 0;
}
6、整体代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//头文件
typedef struct
{
char trainNumber[10]; //车次
int coach; //车厢
int seat; //座号
}Ticket;
//售票函数
int ticketCount = 0; //初始化已售车票数量为0
void sellTicket()
{
Ticket ticket; // 声明一个Ticket类型的局部变量以存储新票的信息
printf("Please enter coach (1-3):\n");
scanf("%d", &ticket.coach);
printf("Please enter seat (1-8):\n");
scanf("%d", &ticket.seat);
// 检查输入是否有效
if (ticket.coach < 1 || ticket.coach > 3 || ticket.seat < 1 || ticket.seat > 8)
{
printf("Input error, please re-enter!\n");
return;
}
// 检查是否已经售出相同的票
int found = 0;
strcpy(ticket.trainNumber, "G1234");
for (int i = 0; i < ticketCount; i++)
{
if (strcmp(tickets[i].trainNumber, ticket.trainNumber) == 0 &&
tickets[i].coach == ticket.coach &&
tickets[i].seat == ticket.seat)
{
printf("Already sold!\n");
found = 1;
break;
}
}
if (found)
{
return; // 如果已经售出,则直接返回,不添加新票
}
// 检查票是否已售完
if (ticketCount >= 3 * 8)
{
printf("The tickets are sold out!\n");
return;
}
tickets[ticketCount++] = ticket;
printf("Ticketing successful!\n");
printf("Here is the ticket information:\n");
printf("Train number:%s\n", ticket.trainNumber);
printf("coach:%d\n", ticket.coach);
printf("Seating:%d\n", ticket.seat);
printf("\n");
}
//退票函数
void refundTicket()
{
char trainNumber[10];
int coach, seat;
printf("Please enter the train number to be refunded:\n");
scanf("%s", trainNumber);
printf("Please enter the coach (1-3) to be refunded:\n");
scanf("%d", &coach);
printf("Please enter the seat to be refunded (1-8):\n");
scanf("%d", &seat);
if (coach < 1 || coach > 3 || seat < 1 || seat > 8)
{
printf("Input error, please re-enter!\n");
return;
}
for(int i = 0;i < ticketCount;i++)
{
if(strcmp(tickets[i].trainNumber,trainNumber) == 0)
{
tickets[i] = tickets[ticketCount - 1];
ticketCount--;
printf("Ticket refund successful! Here is the ticket information:\n");
printf("train number:%s\n", tickets[i].trainNumber);
printf("coach:%d\n", tickets[i].coach);
printf("seat:%d\n", tickets[i].seat);
return;
}
}
printf("Invalid ticket, cannot be refunded:\n");
printf("\n");
}
//查询剩余票函数
void queryRemain()
{
printf("G1234 Remaining seats on the train:\n");
int emptySeats[3][8] = {0}; //记录座位状态
int i, j;
for (i = 0; i < ticketCount; i++)//遍历车票数组
{
if (strcmp(tickets[i].trainNumber, "G1234") == 0)
{
emptySeats[tickets[i].coach - 1][tickets[i].seat - 1] = 1;
}
}
for (i = 0; i < 3; i++)
{
printf("coach %d:", i + 1);
for (j = 0; j < 8; j++)
{
if (emptySeats[i][j] == 0)
{
printf("number%d ", j + 1);
}
}
printf("\n");
}
}
//主函数
int main()
{
int choice;
while(1)
{
printf("****************Welcome to the Train Ticketing System***************\n");
printf("\n 1.sellTicket\n");
printf("\n 2.refundTicket\n");
printf("\n 3.queryRemain\n");
printf("\n 4.exit\n");
printf("\n*********************************************************************\n");
printf("\nPlease select a choice!\n");
scanf("%d",&choice);
switch(choice)
{
case 1:
sellTicket();
break;
case 2:
refundTicket();
break;
case 3:
queryRemain();
break;
case 4:
exit(0);
break;
default:
printf("Invalid ticket, cannot be refunded£¡\n");
}
}
return 0;
}
三、时空复杂度
时间复杂度:Tn = O(1)
空间复杂度:Sn = O(n)
四、运行结果
示例:
第一步,先售票(1车厢1号座)

第二步 尝试购买同一张车票(1车厢1号座),显示该车票已售,无法购买

第三步 退票(1车厢1号座)

第四步 查询剩余车票,退出

