# 数据结构课程设计 —— 设计文档 ## 〇、选题名称 **《火车票务管理系统》** --- ## 一、项目背景与意义 模拟一个小型火车票务平台,乘客可以查询车次、购票、退票、查看换乘方案;管理员可以维护车次信息。 目的是综合运用本学期学过的**线性表、栈、队列、图、查找、排序**这几类数据结构,做一个"看得见、能跑起来"的系统,而不是单独练习某一种数据结构。 --- ## 二、需求分析 ### 2.1 用户角色 | 角色 | 权限 | |---|---| | 管理员 | 增/删/改车次信息,查看销售统计 | | 普通乘客 | 查询车次、购票、退票、查看自己的订单、查询换乘方案 | ### 2.2 功能需求(对应任务书"增删改查排序统计"要求) - **增**:新增车次(管理员);生成购票订单(乘客) - **删**:删除/停运车次(管理员);退票/取消订单(乘客) - **改**:修改车次信息(票价、时间、余票);改签订单 - **查**:按车次号/出发站/到达站/日期查询车次;按身份证号/订单号查询订单;模糊查询 - **排序**:按出发时间、票价、剩余票数排序展示 - **统计**:统计某车次销售量、某线路客流量、某时间段总收入 ### 2.3 非功能需求 - 界面采用菜单驱动(一级菜单 + 二级菜单),文字交互即可,不强制图形界面 - 数据用文件持久化(`.csv`),程序启动时加载,操作后及时写回 - 输入要做基本合法性校验(如车次号不能重复、余票不能为负) --- ## 三、个体数据描述(数据项设计) ### 3.1 车次信息 TrainInfo | 字段 | 说明 | 类型示例 | |---|---|---| | trainNo | 车次号(唯一,如 G1234) | char[8] | | startStation | 始发站 | char[20] | | endStation | 终点站 | char[20] | | departTime | 出发时间 | char[10] | | arriveTime | 到达时间 | char[10] | | price | 票价 | float | | totalSeats | 总票数 | int | | remainSeats | 余票 | int | ### 3.2 订单信息 OrderInfo | 字段 | 说明 | |---|---| | orderId | 订单号(唯一) | | trainNo | 关联车次号 | | passengerName | 乘客姓名 | | idCard | 身份证号(唯一标识乘客,可作哈希查找键) | | seatNo | 座位号 | | orderTime | 购票时间 | | status | 状态:已支付 / 候补中 / 已退票 | ### 3.3 站点/线路信息 Station(供图结构使用) | 字段 | 说明 | |---|---| | stationId | 站点编号 | | stationName | 站点名称 | | adjList | 相邻站点及边权(时长或票价)—— 即图的邻接表 | --- ## 四、数据结构设计(核心部分) 这是整个课程设计评分的重点,下面把"用在哪、为什么用、要实现哪些算法"都列清楚,方便写报告时直接展开。 ### 4.1 车次信息表 —— 顺序表(顺序存储结构) 作为本系统的**主线性表**,对应任务书"线性表若选顺序存储结构"的要求: - 查找:**顺序查找** + **二分查找**(按车次号排序后二分)—— 满足"顺序查找 + 其他查找方式选一种" - 排序:**直接插入排序**(按车次号初始化排序)、**快速排序**(按票价排序)、**堆排序**(按余票数排序)—— 满足"三种以上排序算法" ```c typedef struct { TrainInfo data[MaxSize]; int length; } TrainList; bool ListInsert(TrainList *&L, int i, TrainInfo e); bool ListDelete(TrainList *&L, int i, TrainInfo &e); int SeqSearch(TrainList *L, char trainNo[]); // 顺序查找 int BinSearch(TrainList *L, char trainNo[]); // 二分查找(要求按trainNo有序) void QuickSort(TrainList *&L, int low, int high); // 按票价快排 void HeapSort(TrainList *&L); // 按余票堆排序 ``` ### 4.2 线路网络 —— 图(邻接表存储) 这是本系统的**创新亮点**,对应任务书"图存储结构"的加分项: - 顶点 = 车站,边 = 两站之间存在的车次(边权可设为"时长"或"票价") - **图的两种遍历**:DFS(深度优先,找某站出发能到达的所有站点)、BFS(广度优先,找最少换乘次数的路径) - **最短路径算法(Dijkstra)**:实现"最优换乘路径推荐"——给定起点和终点,算出耗时最短或票价最低的换乘方案 - (可选加分)**最小生成树**:模拟"以最小总里程把所有站点连通"的线路规划场景 ```c typedef struct { int stationId; char stationName[20]; EdgeNode *firstEdge; // 邻接表头指针 } VertexNode; typedef struct EdgeNode { int toStationId; float weight; // 时长或票价 struct EdgeNode *next; } EdgeNode; void DFS(Graph G, int v); void BFS(Graph G, int v); void Dijkstra(Graph G, int src, float dist[], int path[]); // 最优换乘路径 ``` ### 4.3 候补购票队列 —— 队列 当某车次余票为0时,乘客可加入候补队列;一旦有人退票释放余票,按**先进先出**原则自动给候补队列里排在最前面的乘客出票。 ```c typedef struct { OrderInfo data[MaxSize]; int front, rear; } WaitQueue; bool EnQueue(WaitQueue *&Q, OrderInfo e); // 进入候补 bool DeQueue(WaitQueue *&Q, OrderInfo &e); // 候补转正出票 ``` ### 4.4 操作撤销栈 —— 栈 记录最近若干次"购票/退票/改签"操作,支持"撤销上一步",避免误操作(也是一个容易讲的创新点)。 ```c typedef struct { OperationLog data[MaxSize]; int top; } OpStack; bool Push(OpStack *&S, OperationLog op); bool Pop(OpStack *&S, OperationLog &op); // 撤销最近一次操作 ``` ### 4.5 订单快速查找 —— 哈希表 按身份证号哈希定位订单,避免每次都要顺序扫描全部订单,对应"分块查找/哈希表查找选一种"的要求(这里选哈希表)。 ```c int Hash(char idCard[]); // 简单除留余数法或字符累加法 bool HashInsert(OrderInfo orders[], OrderInfo e); OrderInfo* HashSearch(OrderInfo orders[], char idCard[]); ``` > 小结:本系统用到 **顺序表 + 图 + 队列 + 栈 + 哈希表** 五种数据结构,覆盖面广,五个模块分给3人小组刚好可以人均2类结构、4个以上核心函数模块,工作量和创新点都比较容易达标。 --- ## 五、系统功能模块划分(建议3人分工) | 负责人 | 模块 | 核心数据结构 | |---|---|---| | 组员A — 李 | ① 车次信息增删改 ② 顺序/二分查找 ③ 三种排序 ④ 文件读写(trains.csv) | 顺序表 | | 组员B — 刘 | ① 购票下单 ② 退票/改签 ③ 候补排队 ④ 操作撤销栈 | 队列、栈 | | 组员C — 朱 | ① 线路图构建 ② 图的遍历(DFS/BFS) ③ 最短路径换乘推荐 ④ 订单哈希查找与销量统计 | 图、哈希表 | | 共同 | 菜单系统、登录权限、主程序整合 | — | 每人独立完成的模块均≥4个,预计人均代码量400行以上,总代码量轻松超过900行(任务书最低要求)。 --- ## 六、文件存储格式设计 **trains.csv** ``` 车次号,始发站,终点站,出发时间,到达时间,票价,总票数,余票 G1907,北京,上海,08:00,13:28,553.0,800,800 ``` **orders.csv** ``` 订单号,车次号,乘客姓名,身份证号,座位号,购票时间,状态 O00001,G1907,张三,1101**********1234,03A,2026-07-08 09:12,已支付 ``` **stations.csv**(辅助构建图) ``` 站点编号,站点名称,相邻站点(车次号:边权) 1,北京,2:553.0 2,上海,1:553.0;3:120.0 ``` > 建议至少录入30条以上"看起来真实"的车次/乘客数据,可以参考12306的真实城市和车次号编一套,满足"30条以上相对真实个体信息"的要求。 --- ## 七、业务流程(文字版,写报告时可画成流程图) **购票流程**: 登录 → 查询车次(条件查询+排序展示)→ 选择车次 → 判断余票   ├ 有余票 → 生成订单、扣减余票、写回文件   └ 无余票 → 询问是否进入候补队列 → 进入WaitQueue 退票时若有候补,自动从队首取出一人补票。 **换乘查询流程**: 输入起点/终点 → 在图中用Dijkstra计算最短路径(按时长或票价)→ 输出换乘方案(经过哪些站、换乘几次) **数据流向**: 用户输入 → 内存数据结构(顺序表/图/队列/栈/哈希表)→ 算法处理(查找/排序/最短路径)→ 显示结果 → 写回csv文件 --- ## 八、创新点设计(用于答辩加分) 1. **最优换乘路径推荐**(图+Dijkstra)—— 力度最大的创新点 2. **候补购票自动转正**(队列) 3. **操作撤销/回退功能**(栈) 4. **模糊查询/多条件组合查询**(如同时按出发站+价格区间筛选) 5. (可选)简单密码哈希存储,提升登录安全性 > 任务书规定:每个创新点加5分,一组总加分不超过60分。上面5个点选3-4个做扎实,比贪多但都做得浅更划算。 --- ## 九、工作量自查清单 - [ ] 每人源码 ≥ 300行(建议人均400行留余量) - [ ] 总代码量 ≥ 900行 - [ ] 录入 ≥ 30条相对真实的车次/乘客数据 - [ ] 顺序表满足:顺序查找 + 二分查找;三种以上排序算法 - [ ] 图结构满足:两种遍历 + 最短路径算法 - [ ] 报告正文(不含图、代码、运行截图)≥ 3000字 - [ ] 与参考书同类型选题代码重复率 < 50%(本选题与参考书的"通讯录系统"差异较大,基本不存在重复风险) - [ ] 全程使用 C/C++(过程性语言),未使用Python等被禁止的语言 ---