Init Repo

This commit is contained in:
2026-06-26 19:58:32 +08:00
commit 502fad1128
22 changed files with 1626 additions and 0 deletions
+16
View File
@@ -0,0 +1,16 @@
# 编译产物
obj/
*.o
*.exe
train_ticket
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# 系统文件
.DS_Store
Thumbs.db
+18
View File
@@ -0,0 +1,18 @@
MIT License
Copyright (c) 2026 JYUGod
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial
portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+29
View File
@@ -0,0 +1,29 @@
# Makefile - 火车票务管理系统 (C++)
# 编译:mingw32-make 或 makeLinux/Mac
# 清理:mingw32-make clean
CXX = g++
CXXFLAGS = -Wall -Wextra -std=c++17 -g
TARGET = train_ticket.exe
SRCDIR = src
OBJDIR = obj
SRCS = $(wildcard $(SRCDIR)/*.cpp)
OBJS = $(patsubst $(SRCDIR)/%.cpp, $(OBJDIR)/%.o, $(SRCS))
$(TARGET): $(OBJDIR) $(OBJS)
$(CXX) $(CXXFLAGS) -o $@ $(OBJS)
$(OBJDIR):
mkdir -p $(OBJDIR)
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
$(CXX) $(CXXFLAGS) -c $< -o $@
run: $(TARGET)
./$(TARGET)
clean:
rm -rf $(OBJDIR) $(TARGET)
.PHONY: run clean
+250
View File
@@ -0,0 +1,250 @@
# 数据结构课程设计 —— 设计文档
## 〇、选题名称
**《火车票务管理系统》**
---
## 一、项目背景与意义
模拟一个小型火车票务平台,乘客可以查询车次、购票、退票、查看换乘方案;管理员可以维护车次信息。
目的是综合运用本学期学过的**线性表、栈、队列、图、查找、排序**这几类数据结构,做一个"看得见、能跑起来"的系统,而不是单独练习某一种数据结构。
---
## 二、需求分析
### 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等被禁止的语言
---
+51
View File
@@ -0,0 +1,51 @@
# TODO List — 组员A
**负责模块**: 车次信息管理(顺序表)
**核心数据结构**: 顺序表 `TrainList`
**文件**: `src/train.h``src/train.cpp`
**分支**: `feature/train`
---
## 一、顺序表基础操作
- [ ] `ListInsert` — 在位置 i 插入车次(检查越界/满/重复)
- [ ] `ListDelete` — 删除位置 i 的车次(元素前移)
- [ ] `ListUpdate` — 更新位置 i 的车次信息
## 二、查找算法(两种)
- [ ] `SeqSearch` — 顺序查找(按车次号逐个比较)
- [ ] `BinSearch` — 二分查找(需先按 trainNo 排序)
- [ ] `SearchByStation` — 按始发站/终点站模糊查找
- [ ] `AdvancedSearch` — 多条件组合查询(站名 + 票价区间)
## 三、排序算法(三种)
- [ ] `InsertSort` — 直接插入排序(按车次号升序)
- [ ] `QuickSort` — 快速排序(按票价排序)
- [ ] `HeapSort` — 堆排序(按余票数排序)
## 四、文件读写
- [ ] `loadTrainsFromFile` — 从 `data/trains.csv` 读取车次数据
- [ ] `saveTrainsToFile` — 将车次数据写回 `data/trains.csv`
## 五、管理员交互接口
- [ ] `adminAddTrain` — 交互式新增车次(录入各字段,校验合法性)
- [ ] `adminDeleteTrain` — 按车次号查找并删除
- [ ] `adminModifyTrain` — 查找后选择字段修改
- [ ] `adminListTrains` — 遍历输出所有车次(格式化表格)
- [ ] `adminSearchTrain` — 菜单选择查找方式(顺序/二分/模糊)
- [ ] `adminSortTrains` — 菜单选择排序方式(票价快排 / 余票堆排)
- [ ] `adminShowStatistics` — 调用 hash 模块统计函数展示
## 六、乘客交互接口
- [ ] `passengerSearchTrain` — 乘客查车次(按站名/时间/票价筛选)
---
> **依赖关系**: 先完成基础操作(增删改)和文件读写 → 再做查找 → 再做排序 → 最后做交互接口
> **验收标准**: 管理员能完成车次增删改查全流程,排序结果正确,数据重启后不丢失
+63
View File
@@ -0,0 +1,63 @@
# TODO List — 组员B
**负责模块**: 订单管理 + 撤销栈
**核心数据结构**: 候补队列 `WaitQueue`(循环队列)、撤销栈 `OpStack`(顺序栈)
**文件**: `src/order.h``src/order.cpp``src/stack.h``src/stack.cpp`
**分支**: `feature/order`
---
## 一、候补队列(循环队列)
- [ ] `InitQueue` — 初始化队列(front = rear = count = 0
- [ ] `EnQueue` — 候补入队(循环队列,检查队满)
- [ ] `DeQueue` — 候补转正出票(循环队列,检查队空)
- [ ] `QueueEmpty` — 判空
- [ ] `QueueFull` — 判满
## 二、订单操作
- [ ] `GenerateOrderId` — 生成 O00001 格式自增订单号
- [ ] `BuyTicket` — 购票核心逻辑
- 查找车次 → 判断余票
- 有余票:`remainSeats--`,生成订单,`Push` 到撤销栈
- 无余票:询问是否进入候补队列 → `EnQueue`
- [ ] `RefundTicket` — 退票核心逻辑
- 订单状态改为 `REFUNDED`,车次 `remainSeats++`
- 检查候补队列是否非空 → 自动 `DeQueue` 补票
- `Push` 到撤销栈
- [ ] `ChangeTicket` — 改签核心逻辑
- 退原票 + 购新票,更新订单车次号和座位号
- `Push` 到撤销栈
- [ ] `SearchOrdersByIdCard` — 按身份证号查询订单(遍历数组)
- [ ] `SearchOrderById` — 按订单号精确查找
## 三、文件读写
- [ ] `loadOrdersFromFile` — 从 `data/orders.csv` 读取订单数据
- [ ] `saveOrdersToFile` — 将订单数据写回 `data/orders.csv`
## 四、撤销栈(顺序栈)
- [ ] `InitStack` — 初始化(top = -1
- [ ] `Push` — 入栈记录操作日志
- [ ] `Pop` — 出栈获取最近操作
- [ ] `StackEmpty` — 判空
- [ ] `StackFull` — 判满
- [ ] `ExecuteUndo` — 执行撤销
- 购票 → 退票、退票 → 恢复购票、改签 → 改回原车次
- 撤销操作本身不再次入栈
## 五、乘客交互接口
- [ ] `passengerBuyTicket` — 购票菜单交互(选择车次 → 输入姓名/身份证 → 确认购票)
- [ ] `passengerRefundTicket` — 退票菜单交互(输入订单号 → 确认退票)
- [ ] `passengerChangeTicket` — 改签菜单交互(输入订单号 + 新车次号 → 确认改签)
- [ ] `passengerViewOrders` — 查看我的订单(输入身份证号 → 显示所有订单)
- [ ] `passengerUndo` — 撤销菜单交互(显示最近操作 → 确认撤销 → `ExecuteUndo`
---
> **依赖关系**: `order.cpp` 需要 `#include "train.h"`(操作余票)和 `#include "stack.h"`(记录操作)
> **时序关键**: 购票扣减余票 / 退票释放余票 / 候补自动转正 这三个联动的正确性最重要
> **验收标准**: 乘客能完成购票→退票→撤销→候补自动补票全流程,队列 FIFO 顺序正确
+70
View File
@@ -0,0 +1,70 @@
# TODO List — 组员C
**负责模块**: 线路网络图 + 订单哈希查找与统计
**核心数据结构**: 图 `StationGraph`(邻接表)、哈希表 `HashNode`(链地址法)
**文件**: `src/graph.h``src/graph.cpp``src/hash.h``src/hash.cpp`
**分支**: `feature/graph`
---
## 一、图基础操作(邻接表)
- [ ] `InitGraph` — 初始化图(`vertexCount = 0``firstEdge = nullptr`
- [ ] `AddVertex` — 添加站点顶点(检查重复 / 越界)
- [ ] `AddEdge` — 添加线路边(无向图,需同时添加两条边)
- [ ] `FindVertex` — 按 `stationId` 查找顶点下标
## 二、图遍历算法
- [ ] `DFS` — 深度优先遍历(递归实现)
-`startIdx` 出发,标记已访问,输出能到达的所有站点
- [ ] `BFS` — 广度优先遍历(队列辅助)
- 输出最少换乘次数的路径
## 三、最短路径算法(核心加分项)
- [ ] `Dijkstra` — Dijkstra 最短路径算法
- 初始化 `dist[] = INF``visited[] = false``dist[src] = 0`
- 循环选最小未访问顶点,遍历邻接表松弛
- [ ] `PrintPath` — 递归回溯 path[] 数组打印路径
- [ ] `RecommendTransfer` — 换乘推荐入口
- 输入起点/终点站名 → 调用 Dijkstra → 输出换乘方案
- 方案包含:经过站点、换乘次数、总时长/总票价
## 四、最小生成树(可选加分)
- [ ] `PrimMST` — Prim 算法,以最小总里程连通所有站点
## 五、站点文件读写
- [ ] `loadStationsFromFile` — 从 `data/stations.csv` 读取站点和边数据
- 解析顶点行和邻接边(格式: `相邻站点(车次号:边权);...`
- 调用 `AddVertex` / `AddEdge` 构建图
## 六、哈希表操作(链地址法)
- [ ] `Hash` — 哈希函数(身份证号字符累加 % `HASH_SIZE`
- [ ] `InitHashTable` — 初始化所有桶为 `nullptr`
- [ ] `HashInsert` — 插入订单(头插法)
- [ ] `HashSearch` — 按身份证号查找订单
- [ ] `HashSearchByOrderId` — 按订单号查找(遍历所有桶)
- [ ] `HashDelete` — 从哈希表中删除订单
- [ ] `DestroyHashTable` — 释放所有链表节点内存
## 七、统计功能
- [ ] `CountSalesByTrain` — 统计某车次已支付订单数
- [ ] `CountTrafficByRoute` — 统计某线路(始发站-终点站)客流量
- [ ] `CountRevenueByPeriod` — 统计某时间段总收入
- [ ] `HotTrainRanking` — 热门车次排行(按销量降序,取前 N)
## 八、乘客交互接口
- [ ] `passengerFindTransfer` — 换乘查询菜单交互
- 输入起点站名和终点站名 → 调用 `RecommendTransfer`
---
> **依赖关系**: `graph.cpp` 需 `#include <queue>`BFS 辅助队列),`hash.cpp` 需 `#include "train.h"`(统计关联车次表)
> **算法重点**: Dijkstra 是最大加分项,务必写清注释便于答辩
> **验收标准**: 能正确构建线路图,DFS/BFS 遍历正确,Dijkstra 给出最优换乘方案,哈希查找快速定位,统计数据准确
+11
View File
@@ -0,0 +1,11 @@
订单号,车次号,乘客姓名,身份证号,座位号,购票时间,状态
O00001,G101,张三,110101199001011234,01A,2026-06-20 08:00,已支付
O00002,G101,李四,110102199102022345,02B,2026-06-20 08:15,已支付
O00003,G301,王五,320101199203033456,03C,2026-06-20 09:00,已支付
O00004,G401,赵六,440101199304044567,01A,2026-06-20 09:30,已支付
O00005,G501,孙七,610101199405055678,05A,2026-06-20 10:00,已支付
O00006,G101,周八,110103199506066789,03A,2026-06-21 07:30,已支付
O00007,G201,吴九,420101199607077890,02A,2026-06-21 08:00,已退票
O00008,G601,郑十,510101199708088901,01A,2026-06-21 09:00,已支付
O00009,G101,冯十一,110104199809099012,04D,2026-06-22 06:30,已支付
O00010,G701,陈十二,430101199910101023,01A,2026-06-22 07:45,候补中
1 订单号 车次号 乘客姓名 身份证号 座位号 购票时间 状态
2 O00001 G101 张三 110101199001011234 01A 2026-06-20 08:00 已支付
3 O00002 G101 李四 110102199102022345 02B 2026-06-20 08:15 已支付
4 O00003 G301 王五 320101199203033456 03C 2026-06-20 09:00 已支付
5 O00004 G401 赵六 440101199304044567 01A 2026-06-20 09:30 已支付
6 O00005 G501 孙七 610101199405055678 05A 2026-06-20 10:00 已支付
7 O00006 G101 周八 110103199506066789 03A 2026-06-21 07:30 已支付
8 O00007 G201 吴九 420101199607077890 02A 2026-06-21 08:00 已退票
9 O00008 G601 郑十 510101199708088901 01A 2026-06-21 09:00 已支付
10 O00009 G101 冯十一 110104199809099012 04D 2026-06-22 06:30 已支付
11 O00010 G701 陈十二 430101199910101023 01A 2026-06-22 07:45 候补中
+19
View File
@@ -0,0 +1,19 @@
站点编号,站点名称,相邻站点(车次号:边权)
1,北京,2:553.0;3:862.0;5:520.0;9:515.0;17:360.0;21:309.0;31:54.5
2,上海,1:553.0;6:145.0;11:73.0;33:39.5
3,广州,1:862.0;7:74.5;27:314.0
4,深圳,3:74.5;35:225.0
5,武汉,1:520.0;13:164.0;25:130.0
6,南京,2:145.0;15:117.5
7,西安,9:515.0;23:174.5;29:263.0
8,成都,11:154.0;29:263.0
9,重庆,8:154.0
10,长沙,13:164.0;27:314.0
11,杭州,15:117.5;11:73.0
12,沈阳,17:360.0
13,郑州,21:309.0
14,兰州,23:174.5
15,合肥,25:130.0
16,天津,31:54.5
17,苏州,33:39.5
18,厦门,35:225.0
1 站点编号 站点名称 相邻站点(车次号:边权)
2 1 北京 2:553.0;3:862.0;5:520.0;9:515.0;17:360.0;21:309.0;31:54.5
3 2 上海 1:553.0;6:145.0;11:73.0;33:39.5
4 3 广州 1:862.0;7:74.5;27:314.0
5 4 深圳 3:74.5;35:225.0
6 5 武汉 1:520.0;13:164.0;25:130.0
7 6 南京 2:145.0;15:117.5
8 7 西安 9:515.0;23:174.5;29:263.0
9 8 成都 11:154.0;29:263.0
10 9 重庆 8:154.0
11 10 长沙 13:164.0;27:314.0
12 11 杭州 15:117.5;11:73.0
13 12 沈阳 17:360.0
14 13 郑州 21:309.0
15 14 兰州 23:174.5
16 15 合肥 25:130.0
17 16 天津 31:54.5
18 17 苏州 33:39.5
19 18 厦门 35:225.0
+39
View File
@@ -0,0 +1,39 @@
车次号,始发站,终点站,出发时间,到达时间,票价,总票数,余票
G101,北京,上海,06:00,10:28,553.0,800,800
G102,上海,北京,07:00,11:28,553.0,800,800
G103,北京,广州,08:00,16:00,862.0,600,600
G104,广州,北京,09:00,17:00,862.0,600,600
G201,北京,武汉,06:30,10:30,520.0,500,500
G202,武汉,北京,07:30,11:30,520.0,500,500
G301,上海,南京,08:00,09:15,145.0,400,400
G302,南京,上海,09:30,10:45,145.0,400,400
G401,广州,深圳,06:00,06:36,74.5,300,300
G402,深圳,广州,07:00,07:36,74.5,300,300
G501,北京,西安,08:00,12:30,515.0,450,450
G502,西安,北京,09:00,13:30,515.0,450,450
G601,成都,重庆,08:00,09:30,154.0,350,350
G602,重庆,成都,10:00,11:30,154.0,350,350
G701,武汉,长沙,07:00,08:15,164.0,300,300
G702,长沙,武汉,08:30,09:45,164.0,300,300
G801,南京,杭州,09:00,10:15,117.5,380,380
G802,杭州,南京,10:30,11:45,117.5,380,380
G901,北京,沈阳,07:00,10:00,360.0,350,350
G902,沈阳,北京,08:00,11:00,360.0,350,350
G1001,上海,杭州,06:00,06:50,73.0,400,400
G1002,杭州,上海,07:00,07:50,73.0,400,400
G1101,北京,郑州,08:00,10:30,309.0,300,300
G1102,郑州,北京,11:00,13:30,309.0,300,300
G1201,西安,兰州,07:30,10:00,174.5,250,250
G1202,兰州,西安,10:30,13:00,174.5,250,250
G1301,武汉,合肥,08:00,10:00,130.0,200,200
G1302,合肥,武汉,10:30,12:30,130.0,200,200
G1401,广州,长沙,09:00,11:30,314.0,300,300
G1402,长沙,广州,12:00,14:30,314.0,300,300
G1501,成都,西安,07:00,10:30,263.0,280,280
G1502,西安,成都,11:00,14:30,263.0,280,280
G1601,北京,天津,06:30,07:00,54.5,500,500
G1602,天津,北京,07:30,08:00,54.5,500,500
G1701,上海,苏州,08:00,08:25,39.5,450,450
G1702,苏州,上海,08:50,09:15,39.5,450,450
G1801,深圳,厦门,07:00,10:30,225.0,220,220
G1802,厦门,深圳,11:00,14:30,225.0,220,220
1 车次号 始发站 终点站 出发时间 到达时间 票价 总票数 余票
2 G101 北京 上海 06:00 10:28 553.0 800 800
3 G102 上海 北京 07:00 11:28 553.0 800 800
4 G103 北京 广州 08:00 16:00 862.0 600 600
5 G104 广州 北京 09:00 17:00 862.0 600 600
6 G201 北京 武汉 06:30 10:30 520.0 500 500
7 G202 武汉 北京 07:30 11:30 520.0 500 500
8 G301 上海 南京 08:00 09:15 145.0 400 400
9 G302 南京 上海 09:30 10:45 145.0 400 400
10 G401 广州 深圳 06:00 06:36 74.5 300 300
11 G402 深圳 广州 07:00 07:36 74.5 300 300
12 G501 北京 西安 08:00 12:30 515.0 450 450
13 G502 西安 北京 09:00 13:30 515.0 450 450
14 G601 成都 重庆 08:00 09:30 154.0 350 350
15 G602 重庆 成都 10:00 11:30 154.0 350 350
16 G701 武汉 长沙 07:00 08:15 164.0 300 300
17 G702 长沙 武汉 08:30 09:45 164.0 300 300
18 G801 南京 杭州 09:00 10:15 117.5 380 380
19 G802 杭州 南京 10:30 11:45 117.5 380 380
20 G901 北京 沈阳 07:00 10:00 360.0 350 350
21 G902 沈阳 北京 08:00 11:00 360.0 350 350
22 G1001 上海 杭州 06:00 06:50 73.0 400 400
23 G1002 杭州 上海 07:00 07:50 73.0 400 400
24 G1101 北京 郑州 08:00 10:30 309.0 300 300
25 G1102 郑州 北京 11:00 13:30 309.0 300 300
26 G1201 西安 兰州 07:30 10:00 174.5 250 250
27 G1202 兰州 西安 10:30 13:00 174.5 250 250
28 G1301 武汉 合肥 08:00 10:00 130.0 200 200
29 G1302 合肥 武汉 10:30 12:30 130.0 200 200
30 G1401 广州 长沙 09:00 11:30 314.0 300 300
31 G1402 长沙 广州 12:00 14:30 314.0 300 300
32 G1501 成都 西安 07:00 10:30 263.0 280 280
33 G1502 西安 成都 11:00 14:30 263.0 280 280
34 G1601 北京 天津 06:30 07:00 54.5 500 500
35 G1602 天津 北京 07:30 08:00 54.5 500 500
36 G1701 上海 苏州 08:00 08:25 39.5 450 450
37 G1702 苏州 上海 08:50 09:15 39.5 450 450
38 G1801 深圳 厦门 07:00 10:30 225.0 220 220
39 G1802 厦门 深圳 11:00 14:30 225.0 220 220
+106
View File
@@ -0,0 +1,106 @@
/**
* common.h - 火车票务管理系统公共头文件
* 定义所有模块共享的数据类型、常量、枚举
* C++ 版本
*/
#ifndef COMMON_H
#define COMMON_H
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <cstring>
#include <cstdlib>
using namespace std;
/* ==================== 系统常量 ==================== */
constexpr int MAX_TRAINS = 100; // 最大车次数
constexpr int MAX_ORDERS = 500; // 最大订单数
constexpr int MAX_STATIONS = 50; // 最大站点数
constexpr int MAX_QUEUE_SIZE = 100; // 候补队列最大长度
constexpr int MAX_STACK_SIZE = 100; // 撤销栈最大深度
/* ==================== 枚举 ==================== */
// 订单状态
enum class OrderStatus {
PAID, // 已支付
WAITING, // 候补中
REFUNDED // 已退票
};
// 用户角色
enum class UserRole {
ADMIN, // 管理员
PASSENGER // 普通乘客
};
// 操作类型(用于撤销栈)
enum class OpType {
BUY, // 购票
REFUND, // 退票
CHANGE // 改签
};
/* ==================== 结构体定义 ==================== */
// --- 车次信息 ---
struct TrainInfo {
string trainNo; // 车次号(唯一,如 G1234
string startStation; // 始发站
string endStation; // 终点站
string departTime; // 出发时间
string arriveTime; // 到达时间
float price = 0.0f; // 票价
int totalSeats = 0; // 总票数
int remainSeats = 0; // 余票
};
// --- 订单信息 ---
struct OrderInfo {
string orderId; // 订单号(唯一,如 O00001)
string trainNo; // 关联车次号
string passengerName; // 乘客姓名
string idCard; // 身份证号
int seatNo = 0; // 座位号
string orderTime; // 购票时间
OrderStatus status = OrderStatus::PAID; // 订单状态
};
// --- 站点/线路信息 ---
struct EdgeNode {
int toStationId; // 相邻站点编号
float weight; // 边权(时长或票价)
EdgeNode* next = nullptr;// 下一条边
};
struct VertexNode {
int stationId; // 站点编号
string stationName; // 站点名称
EdgeNode* firstEdge = nullptr; // 邻接表头指针
};
// --- 撤销操作日志 ---
struct OperationLog {
OpType type; // 操作类型
string orderId; // 相关订单号
string trainNo; // 相关车次号
int seatNo = 0; // 座位号
string idCard; // 乘客身份证号
string timestamp; // 操作时间
};
// --- 订单状态输出辅助 ---
inline const char* OrderStatusStr(OrderStatus s) {
switch (s) {
case OrderStatus::PAID: return "已支付";
case OrderStatus::WAITING: return "候补中";
case OrderStatus::REFUNDED:return "已退票";
default: return "未知";
}
}
#endif /* COMMON_H */
+104
View File
@@ -0,0 +1,104 @@
/**
* graph.cpp - 线路网络图模块实现(邻接表存储)
* 负责人:组员C
*
* TODO: 组员C 请在此文件中实现所有声明的函数
* C++ 版本
*/
#include "graph.h"
#include <queue> // BFS 可用 STL queue 辅助,或自己用数组模拟
#include <climits> // INT_MAX
/* ==================== 全局变量 ==================== */
StationGraph stationGraph;
/* ==================== 图基础操作 ==================== */
void InitGraph(StationGraph& G) {
// TODO: vertexCount = 0, edgeCount = 0
// 遍历 vertices[]firstEdge = nullptr
}
int AddVertex(StationGraph& G, int stationId, const string& stationName) {
// TODO: 检查是否已存在、是否超过 MAX_STATIONS
// 创建新顶点,vertexCount++
return -1;
}
bool AddEdge(StationGraph& G, int fromId, int toId, float weight) {
// TODO: 无向图,需同时添加两条边
// 1. 创建 EdgeNode{toId, weight} 插入 from 的邻接表头
// 2. 创建 EdgeNode{fromId, weight} 插入 to 的邻接表头
// edgeCount++
return false;
}
int FindVertex(const StationGraph& G, int stationId) {
// TODO: 遍历 vertices[],按 stationId 查找下标
return -1;
}
/* ==================== 图遍历算法 ==================== */
void DFS(const StationGraph& G, int startIdx, bool visited[]) {
// TODO: 递归深度优先遍历
// 1. 标记 visited[startIdx] = true,输出站点名
// 2. 遍历该顶点的邻接表,对每个未访问的邻接点递归 DFS
}
void BFS(const StationGraph& G, int startIdx) {
// TODO: 广度优先遍历,输出最少换乘次数的路径
// 用 queue<int> 辅助
}
/* ==================== 最短路径算法 ==================== */
void Dijkstra(const StationGraph& G, int srcIdx,
float dist[], int path[]) {
// TODO: Dijkstra 最短路径算法
// 1. 初始化 dist[] = INF, visited[] = false
// 2. dist[src] = 0, path[src] = -1
// 3. 循环 vertexCount 次:
// a. 选未访问中 dist 最小的顶点 u
// b. 标记 visited[u] = true
// c. 遍历 u 的邻接表,松弛操作
}
void PrintPath(const StationGraph& G, int path[], int destIdx) {
// TODO: 递归回溯打印路径
// if (path[destIdx] != -1) PrintPath(G, path, path[destIdx])
// cout << G.vertices[destIdx].stationName
}
void RecommendTransfer(const StationGraph& G,
const string& startName, const string& endName) {
// TODO:
// 1. 按站名查找顶点下标
// 2. 调用 Dijkstra
// 3. 调用 PrintPath 输出换乘方案
}
/* ==================== 最小生成树(可选加分) ==================== */
void PrimMST(const StationGraph& G) {
// TODO: Prim 算法实现最小生成树
}
/* ==================== 文件读写 ==================== */
int loadStationsFromFile(const string& filename) {
// TODO: 用 ifstream 读取 CSV
// 解析站点顶点和邻接边,调用 AddVertex / AddEdge 构建图
// 边的格式: "相邻站点(车次号:边权)",多条边用 ; 分隔
return 0;
}
/* ==================== 乘客接口 ==================== */
void passengerFindTransfer() {
// TODO:
// 1. 输入起点站名和终点站名
// 2. 调用 RecommendTransfer
}
+66
View File
@@ -0,0 +1,66 @@
/**
* graph.h - 线路网络图模块(邻接表存储)
* 负责人:组员C
*
* 核心数据结构:图 StationGraph(邻接表)
* 算法:DFS 深度优先遍历、BFS 广度优先遍历、Dijkstra 最短路径
* C++ 版本
*/
#ifndef GRAPH_H
#define GRAPH_H
#include "common.h"
/* ==================== 图结构 ==================== */
struct StationGraph {
VertexNode vertices[MAX_STATIONS]; // 顶点数组
int vertexCount = 0; // 当前顶点数
int edgeCount = 0; // 边数
};
/* ==================== 图基础操作 ==================== */
void InitGraph(StationGraph& G);
int AddVertex(StationGraph& G, int stationId, const string& stationName);
bool AddEdge(StationGraph& G, int fromId, int toId, float weight);
int FindVertex(const StationGraph& G, int stationId);
/* ==================== 图遍历算法 ==================== */
// 深度优先遍历(DFS)—— 递归实现
void DFS(const StationGraph& G, int startIdx, bool visited[]);
// 广度优先遍历(BFS)—— 队列实现,找最少换乘次数路径
void BFS(const StationGraph& G, int startIdx);
/* ==================== 最短路径算法 ==================== */
// Dijkstra 最短路径 —— 最优换乘推荐
// dist[]: 从 src 到各站点的最短距离
// path[]: 前驱节点数组,用于回溯路径
void Dijkstra(const StationGraph& G, int srcIdx,
float dist[], int path[]);
// 打印路径(回溯 path[] 数组)
void PrintPath(const StationGraph& G, int path[], int destIdx);
// 推荐换乘方案(用户接口:输入起点/终点站名,输出最优方案)
void RecommendTransfer(const StationGraph& G,
const string& startName, const string& endName);
/* ==================== 最小生成树(可选加分) ==================== */
// Prim 算法 —— 最小总里程连通所有站点
void PrimMST(const StationGraph& G);
/* ==================== 文件读写 ==================== */
int loadStationsFromFile(const string& filename);
/* ==================== 乘客接口 ==================== */
void passengerFindTransfer();
#endif /* GRAPH_H */
+82
View File
@@ -0,0 +1,82 @@
/**
* hash.cpp - 订单哈希查找与销售统计模块实现
* 负责人:组员C
*
* TODO: 组员C 请在此文件中实现所有声明的函数
* C++ 版本
*/
#include "hash.h"
#include "train.h" // 需要 trainList 做统计关联
/* ==================== 全局变量 ==================== */
HashNode* orderHashTable[HASH_SIZE] = {nullptr};
/* ==================== 哈希表操作 ==================== */
int Hash(const string& idCard) {
// TODO: 哈希函数
// 方案1:取身份证后6位 % HASH_SIZE
// 方案2:逐字符累加 ASCII 值 % HASH_SIZE
return 0;
}
bool HashInsert(HashNode* hashTable[], const OrderInfo& order) {
// TODO: 链地址法插入
// 1. 计算 hash = Hash(order.idCard)
// 2. 创建新 HashNode,头插法插入 hashTable[hash]
return false;
}
const HashNode* HashSearch(HashNode* const hashTable[], const string& idCard) {
// TODO: 哈希查找
// 1. 计算 hash = Hash(idCard)
// 2. 遍历 hashTable[hash] 链表,匹配 idCard
return nullptr;
}
const OrderInfo* HashSearchByOrderId(HashNode* const hashTable[],
const string& orderId) {
// TODO: 按订单号查找(需遍历所有桶)
return nullptr;
}
bool HashDelete(HashNode* hashTable[], const string& orderId) {
// TODO: 哈希删除
// 遍历链表找到目标节点,从链表中移除并 delete
return false;
}
void InitHashTable(HashNode* hashTable[]) {
// TODO: 所有桶置为 nullptr
}
void DestroyHashTable(HashNode* hashTable[]) {
// TODO: 遍历每个桶,释放链表所有节点
}
/* ==================== 统计功能 ==================== */
int CountSalesByTrain(const string& trainNo) {
// TODO: 统计某车次已支付订单数
// 遍历所有桶的链表,匹配 trainNo 且 status == PAID
return 0;
}
int CountTrafficByRoute(const string& startStation, const string& endStation) {
// TODO: 统计某线路客流量
// 需要关联车次表(trainList)判断始发-终点站
return 0;
}
float CountRevenueByPeriod(const string& startTime, const string& endTime) {
// TODO: 统计某时间段总收入
// 匹配 orderTime 在区间内的已支付订单,累加对应车次的票价
return 0.0f;
}
void HotTrainRanking(TrainInfo ranking[], int topN) {
// TODO: 热门车次排行
// 统计每个车次销售量 → 排序 → 取前 topN
}
+54
View File
@@ -0,0 +1,54 @@
/**
* hash.h - 订单哈希查找与销售统计模块
* 负责人:组员C
*
* 核心数据结构:哈希表(链地址法解决冲突)
* 功能:按身份证号快速查找订单、销售统计
* C++ 版本
*/
#ifndef HASH_H
#define HASH_H
#include "common.h"
/* ==================== 哈希表结构 ==================== */
constexpr int HASH_SIZE = 101; // 哈希表大小(素数,减少冲突)
// 哈希表节点(链表)
struct HashNode {
OrderInfo order; // 订单数据
HashNode* next = nullptr; // 链表下一节点
};
/* ==================== 哈希表操作 ==================== */
// 哈希函数(字符累加法 + 除留余数)
int Hash(const string& idCard);
// 插入订单到哈希表
bool HashInsert(HashNode* hashTable[], const OrderInfo& order);
// 按身份证号查找订单
const HashNode* HashSearch(HashNode* const hashTable[], const string& idCard);
// 按订单号查找(顺序扫描哈希表)
const OrderInfo* HashSearchByOrderId(HashNode* const hashTable[],
const string& orderId);
// 删除哈希表中的订单
bool HashDelete(HashNode* hashTable[], const string& orderId);
// 初始化 / 销毁哈希表
void InitHashTable(HashNode* hashTable[]);
void DestroyHashTable(HashNode* hashTable[]);
/* ==================== 统计功能 ==================== */
int CountSalesByTrain(const string& trainNo);
int CountTrafficByRoute(const string& startStation, const string& endStation);
float CountRevenueByPeriod(const string& startTime, const string& endTime);
void HotTrainRanking(TrainInfo ranking[], int topN);
#endif /* HASH_H */
+146
View File
@@ -0,0 +1,146 @@
/**
* main.cpp - 火车票务管理系统主程序
* 负责菜单调度、登录验证、模块整合
* C++ 版本
*/
#include "common.h"
#include "train.h"
#include "order.h"
#include "graph.h"
#include "hash.h"
#include "stack.h"
/* ==================== 全局数据 ==================== */
TrainList trainList; // 车次顺序表
OrderInfo orderArray[MAX_ORDERS]; // 订单数组
int orderCount = 0; // 订单总数
StationGraph stationGraph; // 站点图
WaitQueue* waitQueues[MAX_TRAINS] = {nullptr}; // 候补队列指针数组
OpStack undoStack; // 撤销栈
/* ==================== 文件路径 ==================== */
const string TRAINS_CSV = "../data/trains.csv";
const string ORDERS_CSV = "../data/orders.csv";
const string STATIONS_CSV = "../data/stations.csv";
/* ==================== 菜单函数声明 ==================== */
void showMainMenu();
void showAdminMenu();
void showPassengerMenu();
/* ==================== 主函数 ==================== */
int main() {
cout << "========================================" << endl;
cout << " 火车票务管理系统 v1.0 (C++)" << endl;
cout << "========================================" << endl << endl;
// 加载数据
cout << "正在加载数据..." << endl;
loadTrainsFromFile(TRAINS_CSV);
loadOrdersFromFile(ORDERS_CSV);
loadStationsFromFile(STATIONS_CSV);
cout << "数据加载完成!" << endl << endl;
// 登录选择
int role;
while (true) {
cout << "请选择登录角色:" << endl;
cout << " 1. 管理员" << endl;
cout << " 2. 普通乘客" << endl;
cout << " 0. 退出系统" << endl;
cout << "请输入选项:";
cin >> role;
cin.ignore(); // 吃掉换行符
if (role == 0) {
cout << endl << "正在保存数据..." << endl;
saveTrainsToFile(TRAINS_CSV);
saveOrdersToFile(ORDERS_CSV);
cout << "数据已保存,感谢使用!" << endl;
break;
} else if (role == 1) {
showAdminMenu();
} else if (role == 2) {
showPassengerMenu();
} else {
cout << "输入无效,请重新选择!" << endl << endl;
}
}
return 0;
}
/* ==================== 管理员菜单 ==================== */
void showAdminMenu() {
int choice;
while (true) {
cout << endl;
cout << "========== 管理员菜单 ==========" << endl;
cout << " 1. 新增车次" << endl;
cout << " 2. 删除/停运车次" << endl;
cout << " 3. 修改车次信息" << endl;
cout << " 4. 查看车次列表" << endl;
cout << " 5. 查询车次(按车次号)" << endl;
cout << " 6. 排序车次(按票价/余票/时间)" << endl;
cout << " 7. 查看销售统计" << endl;
cout << " 0. 返回上级菜单" << endl;
cout << "请输入选项:";
cin >> choice;
cin.ignore();
switch (choice) {
case 0: return;
case 1: adminAddTrain(); break;
case 2: adminDeleteTrain(); break;
case 3: adminModifyTrain(); break;
case 4: adminListTrains(); break;
case 5: adminSearchTrain(); break;
case 6: adminSortTrains(); break;
case 7: adminShowStatistics(); break;
default:
cout << "输入无效,请重新选择!" << endl;
}
}
}
/* ==================== 乘客菜单 ==================== */
void showPassengerMenu() {
int choice;
while (true) {
cout << endl;
cout << "========== 乘客菜单 ==========" << endl;
cout << " 1. 查询车次" << endl;
cout << " 2. 购票" << endl;
cout << " 3. 退票" << endl;
cout << " 4. 改签" << endl;
cout << " 5. 查看我的订单" << endl;
cout << " 6. 查询换乘方案" << endl;
cout << " 7. 撤销上一步操作" << endl;
cout << " 0. 返回上级菜单" << endl;
cout << "请输入选项:";
cin >> choice;
cin.ignore();
switch (choice) {
case 0: return;
case 1: passengerSearchTrain(); break;
case 2: passengerBuyTicket(); break;
case 3: passengerRefundTicket(); break;
case 4: passengerChangeTicket(); break;
case 5: passengerViewOrders(); break;
case 6: passengerFindTransfer(); break;
case 7: passengerUndo(); break;
default:
cout << "输入无效,请重新选择!" << endl;
}
}
}
+125
View File
@@ -0,0 +1,125 @@
/**
* order.cpp - 购票/退票/改签模块实现
* 负责人:组员B
*
* TODO: 组员B 请在此文件中实现所有声明的函数
* C++ 版本
*/
#include "order.h"
#include "train.h" // 需要操作车次余票
#include "stack.h" // 需要记录操作日志到撤销栈
/* ==================== 全局变量 ==================== */
OrderInfo orderArray[MAX_ORDERS];
int orderCount = 0;
WaitQueue* waitQueues[MAX_TRAINS] = {nullptr};
/* ==================== 队列操作 ==================== */
void InitQueue(WaitQueue& Q) {
// TODO: 初始化 front = rear = count = 0
}
bool EnQueue(WaitQueue& Q, const OrderInfo& e) {
// TODO: 候补入队(循环队列)
// 检查队满 → 返回 false
// 将 e 存入 data[rear]rear = (rear+1) % MAX_QUEUE_SIZEcount++
return false;
}
bool DeQueue(WaitQueue& Q, OrderInfo& e) {
// TODO: 候补转正出票(循环队列)
// 检查队空 → 返回 false
// 取出 data[front]front = (front+1) % MAX_QUEUE_SIZEcount--
return false;
}
bool QueueEmpty(const WaitQueue& Q) {
// TODO: count == 0
return true;
}
bool QueueFull(const WaitQueue& Q) {
// TODO: count == MAX_QUEUE_SIZE
return false;
}
/* ==================== 订单操作 ==================== */
string GenerateOrderId() {
// TODO: 生成 O00001 格式的自增订单号
// 用静态变量记录已生成的序号
return "O00000";
}
int BuyTicket(const OrderInfo& order) {
// TODO: 购票逻辑
// 1. 查出对应车次(trainList 中查找)
// 2. 判断 remainSeats > 0
// a. 有余票 → remainSeats--,生成订单,存入 orderArray
// 将操作 Push 到 undoStack
// b. 无余票 → 询问是否进入候补队列 → EnQueue
return -1;
}
int RefundTicket(const string& orderId) {
// TODO: 退票逻辑
// 1. 找到订单,status 改为 REFUNDED
// 2. 对应车次 remainSeats++
// 3. 检查该车次候补队列是否非空:
// a. DeQueue → 自动为候补乘客出票,remainSeats--
// 4. 将操作 Push 到 undoStack
return -1;
}
int ChangeTicket(const string& orderId, const string& newTrainNo) {
// TODO: 改签逻辑
// 1. 原订单退票(释放原车次余票)
// 2. 在新车次购票(扣减新车次余票)
// 3. 更新订单的 trainNo 和 seatNo
// 4. Push 到 undoStack
return -1;
}
int SearchOrdersByIdCard(const string& idCard,
OrderInfo results[], int maxResults) {
// TODO: 遍历 orderArray,按 idCard 匹配
return 0;
}
const OrderInfo* SearchOrderById(const string& orderId) {
// TODO: 遍历 orderArray,按 orderId 匹配,返回指针
return nullptr;
}
/* ==================== 文件读写 ==================== */
int loadOrdersFromFile(const string& filename) {
// TODO: 用 ifstream 读取 CSV,填充 orderArray
return 0;
}
int saveOrdersToFile(const string& filename) {
// TODO: 用 ofstream 写回 CSV
return 0;
}
/* ==================== 乘客接口 ==================== */
void passengerBuyTicket() {
// TODO: 交互:选择车次 → 输入姓名/身份证 → 生成订单
}
void passengerRefundTicket() {
// TODO: 交互:输入订单号 → 执行退票
}
void passengerChangeTicket() {
// TODO: 交互:输入订单号 + 新车次号 → 执行改签
}
void passengerViewOrders() {
// TODO: 交互:输入身份证号 → 显示该乘客所有订单
}
+64
View File
@@ -0,0 +1,64 @@
/**
* order.h - 购票/退票/改签模块(订单管理)
* 负责人:组员B
*
* 核心数据结构:候补队列 WaitQueue(队列)
* C++ 版本
*/
#ifndef ORDER_H
#define ORDER_H
#include "common.h"
/* ==================== 候补队列结构 ==================== */
struct WaitQueue {
OrderInfo data[MAX_QUEUE_SIZE];
int front = 0; // 队首下标
int rear = 0; // 队尾下标
int count = 0; // 当前队列长度
};
/* ==================== 队列操作 ==================== */
void InitQueue(WaitQueue& Q);
bool EnQueue(WaitQueue& Q, const OrderInfo& e);
bool DeQueue(WaitQueue& Q, OrderInfo& e);
bool QueueEmpty(const WaitQueue& Q);
bool QueueFull(const WaitQueue& Q);
/* ==================== 订单操作 ==================== */
// 生成订单号(自增格式化)
string GenerateOrderId();
// 购票
int BuyTicket(const OrderInfo& order);
// 退票(若有候补自动转正)
int RefundTicket(const string& orderId);
// 改签
int ChangeTicket(const string& orderId, const string& newTrainNo);
// 按身份证号查询订单,返回匹配数量
int SearchOrdersByIdCard(const string& idCard,
OrderInfo results[], int maxResults);
// 按订单号查询
const OrderInfo* SearchOrderById(const string& orderId);
/* ==================== 文件读写 ==================== */
int loadOrdersFromFile(const string& filename);
int saveOrdersToFile(const string& filename);
/* ==================== 乘客接口 ==================== */
void passengerBuyTicket();
void passengerRefundTicket();
void passengerChangeTicket();
void passengerViewOrders();
#endif /* ORDER_H */
+64
View File
@@ -0,0 +1,64 @@
/**
* stack.cpp - 操作撤销栈模块实现
* 负责人:组员B
*
* TODO: 组员B 请在此文件中实现所有声明的函数
* C++ 版本
*/
#include "stack.h"
#include "order.h" // 需要调用 RefundTicket / BuyTicket 执行逆操作
/* ==================== 全局变量 ==================== */
OpStack undoStack;
/* ==================== 栈操作 ==================== */
void InitStack(OpStack& S) {
// TODO: top = -1
}
bool Push(OpStack& S, const OperationLog& op) {
// TODO: 检查栈满 → false
// top++data[top] = op
return false;
}
bool Pop(OpStack& S, OperationLog& op) {
// TODO: 检查栈空 → false
// op = data[top]top--
return false;
}
bool StackEmpty(const OpStack& S) {
// TODO: top == -1
return true;
}
bool StackFull(const OpStack& S) {
// TODO: top == MAX_STACK_SIZE - 1
return false;
}
/* ==================== 撤销功能 ==================== */
int ExecuteUndo(OpStack& S) {
// TODO:
// 1. Pop 出一个 OperationLog
// 2. 根据其 type 执行逆操作:
// BUY → 调用 RefundTicket
// REFUND → 调用 BuyTicket(恢复原订单)
// CHANGE → 改回原车次
// 3. 注意:撤销操作本身不再次入栈
return -1;
}
/* ==================== 乘客接口 ==================== */
void passengerUndo() {
// TODO:
// 1. 判断 undoStack 是否为空
// 2. 显示最近操作信息,询问是否确认撤销
// 3. 执行 ExecuteUndo
}
+40
View File
@@ -0,0 +1,40 @@
/**
* stack.h - 操作撤销栈模块
* 负责人:组员B
*
* 核心数据结构:顺序栈 OpStack
* 功能:记录最近操作,支持撤销购票/退票/改签
* C++ 版本
*/
#ifndef STACK_H
#define STACK_H
#include "common.h"
/* ==================== 栈结构 ==================== */
struct OpStack {
OperationLog data[MAX_STACK_SIZE];
int top = -1; // 栈顶下标,-1 表示栈空
};
/* ==================== 栈操作 ==================== */
void InitStack(OpStack& S);
bool Push(OpStack& S, const OperationLog& op);
bool Pop(OpStack& S, OperationLog& op);
bool StackEmpty(const OpStack& S);
bool StackFull(const OpStack& S);
/* ==================== 撤销功能 ==================== */
// 执行撤销(调用对应的逆操作)
// 购票→退票,退票→购票,改签→改回原车次
int ExecuteUndo(OpStack& S);
/* ==================== 乘客接口 ==================== */
void passengerUndo();
#endif /* STACK_H */
+129
View File
@@ -0,0 +1,129 @@
/**
* train.cpp - 车次信息管理模块实现(顺序表)
* 负责人:组员A
*
* TODO: 组员A 请在此文件中实现所有声明的函数
* C++ 版本
*/
#include "train.h"
/* ==================== 全局变量 ==================== */
TrainList trainList;
/* ==================== 基础操作 ==================== */
bool ListInsert(TrainList& L, int i, const TrainInfo& e) {
// TODO: 在位置 i 插入车次
// 检查合法性(i 范围、表是否满、车次号是否重复)
// 将位置 i 及之后元素后移一位
// 插入新元素,length++
return false;
}
bool ListDelete(TrainList& L, int i, TrainInfo& e) {
// TODO: 删除位置 i 的车次,结果存入 e
// 将位置 i+1 及之后元素前移一位
// length--
return false;
}
bool ListUpdate(TrainList& L, int i, const TrainInfo& e) {
// TODO: 更新位置 i 的车次信息
return false;
}
/* ==================== 查找算法 ==================== */
int SeqSearch(const TrainList& L, const string& trainNo) {
// TODO: 顺序查找,逐个比较 trainNo
// 找到返回下标,未找到返回 -1
return -1;
}
int BinSearch(const TrainList& L, const string& trainNo) {
// TODO: 二分查找(前提:顺序表按 trainNo 有序)
// 使用 InsertSort 排序后再查找
return -1;
}
int SearchByStation(const TrainList& L, const string& keyword,
TrainInfo results[], int maxResults) {
// TODO: 按站名模糊查找(在 startStation / endStation 中匹配)
return 0;
}
int AdvancedSearch(const TrainList& L, const string& startStation,
const string& endStation, float minPrice,
float maxPrice, TrainInfo results[], int maxResults) {
// TODO: 多条件组合查询
return 0;
}
/* ==================== 排序算法 ==================== */
void InsertSort(TrainList& L) {
// TODO: 直接插入排序(按车次号升序)
// 将 trainNo 字符串比较,从小到大排列
}
void QuickSort(TrainList& L, int low, int high) {
// TODO: 快速排序(按票价排序)
}
void HeapSort(TrainList& L) {
// TODO: 堆排序(按余票数排序)
// 构建大顶堆 / 小顶堆
}
/* ==================== 文件读写 ==================== */
int loadTrainsFromFile(const string& filename) {
// TODO: 用 ifstream 读取 CSV 文件
// 跳过标题行,逐行解析字段填充 TrainInfo
// 存入 trainList
return 0;
}
int saveTrainsToFile(const string& filename) {
// TODO: 用 ofstream 写回 CSV 文件
// 先写标题行,再逐行输出 trainList 数据
return 0;
}
/* ==================== 管理员接口 ==================== */
void adminAddTrain() {
// TODO: 交互式录入新 TrainInfo,调用 ListInsert
}
void adminDeleteTrain() {
// TODO: 输入车次号,SeqSearch 找到后调用 ListDelete
}
void adminModifyTrain() {
// TODO: 查找后修改字段,调用 ListUpdate
}
void adminListTrains() {
// TODO: 遍历 trainList 输出所有车次
}
void adminSearchTrain() {
// TODO: 提示选择查找方式(顺序/二分/站名模糊)
}
void adminSortTrains() {
// TODO: 提示选择排序方式(票价快排 / 余票堆排)
}
void adminShowStatistics() {
// TODO: 调用 hash 模块的统计函数展示
}
/* ==================== 乘客接口 ==================== */
void passengerSearchTrain() {
// TODO: 乘客查车次(支持按站名、时间、票价区间筛选)
}
+80
View File
@@ -0,0 +1,80 @@
/**
* train.h - 车次信息管理模块(顺序表)
* 负责人:组员A
*
* 核心数据结构:顺序表 TrainList
* 算法:顺序查找、二分查找、直接插入排序、快速排序、堆排序
* C++ 版本
*/
#ifndef TRAIN_H
#define TRAIN_H
#include "common.h"
/* ==================== 顺序表结构 ==================== */
struct TrainList {
TrainInfo data[MAX_TRAINS];
int length = 0;
};
/* ==================== 基础操作 ==================== */
// 增:在位置 i 插入车次
bool ListInsert(TrainList& L, int i, const TrainInfo& e);
// 删:删除位置 i 的车次,将删除的元素存入 e
bool ListDelete(TrainList& L, int i, TrainInfo& e);
// 改:更新车次信息
bool ListUpdate(TrainList& L, int i, const TrainInfo& e);
/* ==================== 查找算法 ==================== */
// 顺序查找(按车次号),返回下标,未找到返回 -1
int SeqSearch(const TrainList& L, const string& trainNo);
// 二分查找(要求顺序表按 trainNo 有序),返回下标,未找到返回 -1
int BinSearch(const TrainList& L, const string& trainNo);
// 按始发站/终点站模糊查找,返回匹配数量
int SearchByStation(const TrainList& L, const string& keyword,
TrainInfo results[], int maxResults);
// 多条件组合查询
int AdvancedSearch(const TrainList& L, const string& startStation,
const string& endStation, float minPrice,
float maxPrice, TrainInfo results[], int maxResults);
/* ==================== 排序算法 ==================== */
// 直接插入排序(按车次号排序)
void InsertSort(TrainList& L);
// 快速排序(按票价排序)
void QuickSort(TrainList& L, int low, int high);
// 堆排序(按余票数排序)
void HeapSort(TrainList& L);
/* ==================== 文件读写 ==================== */
int loadTrainsFromFile(const string& filename);
int saveTrainsToFile(const string& filename);
/* ==================== 管理员接口 ==================== */
void adminAddTrain();
void adminDeleteTrain();
void adminModifyTrain();
void adminListTrains();
void adminSearchTrain();
void adminSortTrains();
void adminShowStatistics();
/* ==================== 乘客接口 ==================== */
void passengerSearchTrain();
#endif /* TRAIN_H */