全国交通资讯系统
1. 题目
1.1 问题描述 设计、实现一个全国大城市间的交通咨询程序,为旅客提供三种最优决策方案: (1)时间最短 (2)费用最小 (3)中转次数最少。
1.2 实现提示
该程序所做的工作的是模拟全国交通咨询,为旅客提供三种最优决策的交通咨询。 (1)在程序中输入城市名称时,需输入10个字母以内的字母串;输入列车或飞机编号时需输入一个整型数据;输入列车或飞机的费用时需输入一个实型数据;输入列车或飞机开始时间和到达时间时均需输入两个整型数据(以hh:mm的形式);在选择功能时,应输入与所选功能对应的一个整型数据。
(2)程序的输出信息主要是:最快需要多少时间才能到达,或最少需要多少旅费才能到达,或最少需要多少次中转到达,并详细说明依次于何时乘坐哪一趟列车或哪一次班机到何地。
(3)程序的功能包括:提供对城市信息的编辑,提供列车时刻表和飞机航班表的编辑,提供三种最优决策:最快到达、最省钱到达、最少中转次数到达。
测试数据:
航班时刻表:
出发城市 | 到达城市 | 班次名 | 出发时间 | 到达时间 | 用时 | 票价 |
---|---|---|---|---|---|---|
北京 | 上海 | MU6320 | 16:20 +0 | 17:25 +0 | 01:5 +0 | 680.00 |
北京 | 乌鲁木齐 | CA2104 | 08:00 +0 | 09:55 +0 | 01:55 +0 | 1150.00 |
北京 | 西安 | MC201 | 15:25 +0 | 17:0 +0 | 02:35 +0 | 930.00 |
西安 | 北京 | MC201 | 12:35 +0 | 14:15 +0 | 02:40 +0 | 930.00 |
西安 | 广州 | CM2323 | 07:15 +0 | 09:35 +0 | 02:20 +0 | 1320.00 |
上海 | 北京 | MU6320 | 18:00 +0 | 19:5 +0 | 01:5 +0 | 680.00 |
广州 | 西安 | CM2323 | 10:15 +0 | 11:35 +0 | 01:20 +0 | 1320.00 |
广州 | 武汉 | CM4723 | 11:25 +0 | 13:5 +0 | 02:40 +0 | 810.00 |
昆明 | 拉萨 | MA173 | 12:35 +0 | 14:0 +0 | 02:25 +0 | 830.00 |
昆明 | 乌鲁木齐 | CA82 | 13:05 +0 | 15:50 +0 | 02:45 0 | 1480.00 |
武汉 | 拉萨 | MC3304 | 16:25 +0 | 17:55 +0 | 01:30 +0 | 890.00 |
武汉 | 广州 | CM4723 | 07:05 +0 | 08:45 +0 | 01:40 +0 | 810.00 |
乌鲁木齐 | 北京 | CA2104 | 10:45 +0 | 11:40 +0 | 01:55 +0 | 1150.00 |
乌鲁木齐 | 昆明 | CA82 | 09:30 +0 | 12:15 +0 | 03:45 +0 | 1480.00 |
拉萨 | 昆明 | MA173 | 10:20 +0 | 11:45 +0 | 01:25 +0 | 830.00 |
拉萨 | 武汉 | MC3304 | 14:15 +0 | 15:45 +0 | 01:30 +0 | 890.00 |
列车时刻表:
出发城市 | 到达城市 | 班次名 | 出发时间 | 到达时间 | 用时 | 票价 |
---|---|---|---|---|---|---|
北京 | 郑州 | K27 | 13:15 +0 | 21:12 +0 | 08:57 +0 | 78.00 |
北京 | 郑州 | T41 | 07:11 +0 | 15:8 +0 | 08:57 +0 | 90.00 |
北京 | 兰州 | T134 | 19:24 +0 | 10:28 +1 | 15:4 +0 | 162.00 |
郑州 | 西安 | T27 | 21:24 +0 | 05:13 +1 | 08:49 +0 | 82.00 |
郑州 | 北京 | K27 | 13:42 +0 | 21:40 +0 | 08:58 +0 | 78.00 |
郑州 | 北京 | T41 | 09:40 +0 | 17:37 +0 | 08:57 +0 | 90.00 |
郑州 | 上海 | K41 | 15:20 +0 | 00:13 +1 | 09:53 +0 | 100.00 |
西安 | 郑州 | T27 | 05:41 +0 | 13:30 +0 | 08:49 +0 | 82.00 |
西安 | 武汉 | K218 | 01:34 +0 | 18:35 +0 | 17:1 +0 | 178.00 |
上海 | 郑州 | K41 | 00:35 +0 | 09:28 +0 | 09:53 +0 | 100.00 |
上海 | 广州 | K59 | 08:20 +0 | 03:16 +1 | 19:56 +0 | 182.00 |
广州 | 上海 | K59 | 03:39 +0 | 22:53 +0 | 19:14 +0 | 182.00 |
广州 | 昆明 | K323 | 06:18 +0 | 16:14 +0 | 10:56 +0 | 102.00 |
广州 | 长沙 | T373 | 00:35 +0 | 11:35 +0 | 11:0 +0 | 116.00 |
兰州 | 北京 | T134 | 03:52 +0 | 18:56 +0 | 15:4 +0 | 162.00 |
兰州 | 武汉 | K747 | 17:41 +0 | 14:47 +1 | 21:6 +0 | 210.00 |
兰州 | 乌鲁木齐 | T371 | 11:42 +0 | 23:54 +0 | 12:12 +0 | 114.00 |
昆明 | 广州 | K323 | 16:31 +0 | 02:27 +1 | 10:56 +0 | 102.00 |
昆明 | 武汉 | T873 | 21:42 +0 | 11:46 +1 | 14:4 +0 | 134.00 |
武汉 | 昆明 | T873 | 07:13 +0 | 21:17 +0 | 14:4 +0 | 134.00 |
武汉 | 长沙 | K116 | 09:36 +0 | 18:32 +0 | 09:56 +0 | 98.00 |
武汉 | 兰州 | K747 | 15:13 +0 | 12:19 +1 | 21:6 +0 | 210.00 |
武汉 | 西安 | K218 | 18:50 +0 | 11:51 +1 | 17:1 +0 | 178.00 |
长沙 | 武汉 | K116 | 18:54 +0 | 03:48 +1 | 09:54 +0 | 98.00 |
长沙 | 广州 | T373 | 13:15 +0 | 00:15 +1 | 11:0 +0 | 116.00 |
乌鲁木齐 | 兰州 | T371 | 00:35 +0 | 11:23 +0 | 11:48 +0 | 114.00 |
安徽 | 郑州 | T555 | 15:20 +0 | 20:35 +0 | 05:15 +0 | 310.00 |
2.主要功能函数
1.迪杰斯卡尔算法计算最少花费函数;2.迪杰斯卡尔算法计算花费最少时间函数;3.迪杰斯卡尔算法计算最少中转次数函数;4.计算并输出路径函数;5.保存用户和管理员密码账户到文件函数;6.从文件里导入管理员和用户账号密码函数;7.用户登录函数;8.用户注册账号密码函数;9.用户修改密码函数;10.管理员登录函数;11.管理员注册账号密码函数;12.管理员修改密码函数;13.主菜单界面;14.一级用户菜单界面;15.二级用户功能菜单界面;16.一级管理员用户菜单界面;17.二级管理员功能菜单界面主函;18.整合所有的子函数并且在所有界面函数里调用调试。
19.链栈所有操作函数及其数据结构定义1.输入时间;2.计算所用时间函数;3.输出时间函数;4.查询城市编号;5.调整图的存储大小;6.手动添加城市;7.从文件中读取添加城市;8.添加路线;9.插入线;10.从文件插入路线;
1.利用结点及指针删除指定序号的路线信息;2.判断飞机或火车路线有列车经过的城市数量;3.删除以城市为结点的所有航班或火车路线;4.显示起点城市到终点城市所有路线信息;5.显示系统中所有城市信息;6.显示系统中所有路线信息(包括有出发城市,到达城市,班次名,出发时间,到达时间,用时,票价);7.删除指定的路线信息;8.保存数据到文件中;
3. 需求分析
(1) 提供两种管理员身份和普通用户身份进行操作,管理员和用户身份信息保存到文件里,程序运行时直接导入。
(2) 提供管理员对城市信息进行编辑(如:添加或删除)的功能。既可以从文件直接导入,也可以手动添加输入。 (3) 管理员查看所有城市信息。
(4) 管理员查看所有路线信息。 (5) 管理员保存系统信息到文件里。 (6) 管理员添加城市路线信息。
(7) 管理员输入路线信息时,系统根据管理员输入的起始时间和终点自动计算花费的时间。 (8) 管理员可以注册账号,登陆账号,修改密码功能。
(9) 提供用户查看两个城市之间的所有火车班次或者飞机航班。 (10) 用户可以查询三种最优决策:最快到达,最省钱到达以及最少中转次数到
达。
(11) 城市之间有两种交通工具:火车和飞机。提供管理员对列车时刻表和飞机航班进行编辑(增设或删除)的功能。也可以从文件中一键导入信息。
(12) 旅途中耗费的总时间应该包括中转站的等候时间。 (13) 不同界面之间转换要体验感比较好,来回切换。
(14) 由使用者选择管理员身份或普通用户身份,进入不同的界面。
4. 概要设计
4.1 数据结构 定义时间结构体 typedef struct { int day; int hour; int minute;
}Time; 定义边结点信息结构体 typedef struct InforType { char
LineName[10];//航班号或火车车次 int LineType;//1 飞机 2火车 Time StartTime,
EndTime;//航班或火车的出发时间和达到时间 Time SpendTime;//所用总时间 float Money;//票价
}TrafficLine; 定义图中邻接表里面的边结构体 typedef struct ArcNode {//边表 char
EndName[10]; struct ArcNode* nextline; TrafficLine* Info;//该边的路线信息
}LineNode; 定义图中邻接表里面的顶点结构体 typedef struct VNode {//顶点表 char
CityName[10];//城市名 int CityOrder;//城市编号 LineNode*
firstline;//指向第一个后继表的指针 int Amount;//该城市的总班次 }VNode, Vnode[50];
定义图结构体 typedef struct { Vnode CityList;//城市 int CityNum;//城市个数(顶点数)
int MaxCityNum;//当前最大城市个数 int ArcNum;//路线数(边数) }ALGraph; 定义链栈结点结构体
typedef struct StackNode { int data; struct StackNode* next;
}StackNode,*LinkStack; //初始化 定义迪杰斯特拉算法求最少费用的源点结构体 struct Node { int
id; //源顶点id float money; //(费用) friend bool operator < (struct
Node a, struct Node b) { return a.money > b.money; } };
定义迪杰斯特拉算法求最少中转次数的源点结构体struct TranNode { //记录最少中转次数结构体 int id; int count; friend bool
operator < (struct TranNode a, struct TranNode b) { return a.count >
b.count; }}; 定义迪杰斯特拉算法求最少花费时间的源点结构体 struct Node1 { int id; //源顶点id int tt;
//(时间) Time et; //到达时间 friend bool operator < (struct Node1 a,
struct Node1 b) { return a.tt > b.tt; } }; 定义用户结构体数组 struct user {
char szName[20];//定义用户名 char password1[20];//定义用户账户密码 char
password2[20];//定义用户二次输入密码 int nSerialNum;//定义用户序号(从1开始) }user[10];定义管理员的结构体数组 struct admini { char szName[20];//定义管理员用户名 char
password1[20];//定义管理员账户密码 char password2[20];//定义管理员二次输入密码 int
nSerialNum;//定义管理员序号(从1开始) }admini[10];4.2 程序模块 输入时间 void InputTime(TrafficLine& temp)void SpendTime(TrafficLine& temp) 计算所用时间函数 void SpendTime(TrafficLine&
temp) 输出时间函数 void Outputtime(Time t) 查询城市编号 int SearchCityNum(char
CityName[]) 手动添加城市 void AddCity(char Cityname[]) 从文件中读取添加城市 void
AddCityFile(char FileName[]) 添加路线 void AddLine() 插入线 void
InsertLine(char Startcity[], char Endcity[], LineNode* temp) 从文件插入路线
void AddLineFile(char FileName[]) 删除序号为i的城市所有路线 void DelCityLine(int
i) 判断图中有火车路线的城市数量 int TrainNum() 判断图中有飞机路线的城市数量 int FlightNum()
删除以城市为节点的所有航班,火车路线 void DelCity(char CityName[]) 显示起点城市到终点城市所有路线信息
bool ShowLine(char startname[], char endname[]) void ShowLine(int
start, int end) 显示系统中所有城市信息 void ShowCity() 显示系统中所有路线信息 void
ShowLine() 删除路线 void DelLine() 保存数据到文件中 void UpdataFile(char
FileName[], char type[]) 初始化 int InitStack(LinkStack& S) 入栈 int
Push(LinkStack& S, int e) 出栈 int Pop(LinkStack& S, int& e) { 取栈顶元素 int
GetTop(LinkStack S) 判空 bool Empty(LinkStack S) 迪杰斯卡尔算法计算最少花费 void
Dijkstra_Money(int v0, int* parent, Node* dis) 迪杰斯卡尔算法计算最少中转 void
Dijkstra_Tran(int v0, int* parent, TranNode* dis) 计算转站时间 int
TimeTransWeight(const Time& t1, const Time& t2) 计算时间转化为分钟数 int
TimeWeight(const Time& t) 迪杰斯卡尔算法计算最少时间路线 void Dijkstra_Time(int v0,
int* parent, Node1* dis) { 显示输出最短路径 void ShowShortestPath(const char
type[]) 保存管理员和用户所有密码账号信息到文件 void SaveFile(FILE* fp) 从文件里读出管理员和用户信息
void ReadFile(FILE* fp) 用户注册账号 void User_Register(FILE* fp) 用户登录 void
User_Logon() 用户修改密码 void User_ResetPassword(FILE* fp) 管理员创建账户 void
Admini_Register(FILE* fp) 管理员登录 void Admini_Logon() 管理员修改密码 void
Admini_ResetPassword(FILE* fp) 二级用户菜单 void SencondUser_Meau(); 一级用户菜单
void user_Meau(); 一级管理员菜单 void admini_Meau(); 二级管理员菜单 void
Sencondadmini_Meau(); 主菜单 void FirstMeau() 主函数 int main()4.3 各模块之间的调用关系以及算法设计
4.3.1 调用关系: void FirstMeau() void user_Meau();
void admini_Meau();void User_Register(FILE* fp)
void user_Meau(); void User_Logon()
void User_ResetPassword(FILE* fp)
void Admini_Register(FILE* fp)
void admini_Meau(); void Admini_Logon()
void Admini_ResetPassword(FILE* fp)
4.3.2 算法设计: Dijkstra(迪杰斯特拉)算法是典型的最短路径路由算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法能得出最短路径的最优解,但由于它遍历计算的节点很多,所以效率低。基本思想是,设置顶点集合S并不断地作贪心选择来扩充这个集合。一个顶点属于集合S当且仅当从源到该顶点的最短路径长度已知。初始时,S中仅含有源。设u是G的某一个顶点,把从源到u且中间只经过S中顶点的路称为从源到u的特殊路径,并用数组dis记录当前每个顶点所对应的最短特殊路径长度。Dijkstra算法每次从V-S中取出具有最短特殊路长度的顶点u,将u添加到S中,同时对数组dis作必要的修改。一旦S包含了所有V中顶点,dis就记录了从源到所有其它顶点之间的最短路径长度。
5. 详细设计
主要操作写出实现算法 迪杰斯特拉算法实现代码: //最少花费路径 struct Node { int id; //源顶点id
float money; //(费用) friend bool operator < (struct Node a, struct
Node b) { return a.money > b.money; } }; //迪杰斯卡尔算法计算最少花费 void
Dijkstra_Money(int v0, int* parent, Node* dis) { priority_queue
q; //队列存储最短距离与索引的编号 //parent[]记录每个顶点的父亲结点
//dis[]记录源点到每个估算距离,最后更新为源点到所有顶点的最短距离 bool visited[50] = { false };
//判断下标对应的顶点是否算出最短路径int i; for (i = 0; i < G.CityNum; ++i) {//初始化 dis[i].id = i;
dis[i].money = INF; parent[i] = -1; //每个顶点都没有父结点 visited[i]
= false; //都未找到最短路 } dis[v0].money = 0; //源点到源点最短路权值为0 q.push(dis[v0]); //压入队列 while (!q.empty()) {
//队列空说明完成了求解v0到其余各顶点的最短路径 Node cd = q.top(); //取最小费用顶点 q.pop();
int u = cd.id;if (visited[u]) { //被标记了,就无需对其进行更新最短距离等等操作 continue; } visited[u] = true; LineNode* p = G.CityList[u].firstline; //松弛操作 while (p) { //找所有与它相邻的顶点,进行松弛操作,更新估算费用,压入队列 int v =
SearchCityNum(p->EndName); float m = p->Info->Money; if
(!visited[v] && dis[v].money > dis[u].money + m) {
dis[v].money = dis[u].money + m;
parent[v] = u;
q.push(dis[v]); } p = p->nextline; } }// while (!q.empty()) }//dijkstra_Money
6 测试输出的结果:
6.3 时间复杂度分析: 考虑到道路网多是稀疏网,故采用了邻接表作存储结构,其空间复杂度位0(e),此时的时间复杂度也为0(e)。构建邻接表的时间复杂度为O(n+e),输出路径的时间复杂度为0(nn)。由此,本交通资讯系统的时间复杂度位0(nn)
6.4 算法的改进设想等: 本程序在求最短路径时使用了迪杰斯特拉算法,主要考虑在本程序的初级阶段,并不需要大量的查询,更多会是图信息的添加和修改,重在算法的理解和掌握,因此采用了算法复杂度相对较低的迪杰斯特拉算法。当然,从性能上来说,当交通图基本稳定,而且城市信息基本完善的时候,使用佛洛伊德把所有的最短路径信息存储起来可能会更方便一点,后续的查询的时间复杂度也会相对降低。由此可见,在选用算法时,不能单纯地只考虑算法的时间复杂度,有时还必须综合考虑各种因素。对于迪杰斯特拉算法求最少中转路径时,对于相同中转次数的选择是随机选择的,算法实现特定选择需要改进。
7. 用户使用说明
7.1 管理员使用说明: 管理员使用之前,如有账号,就可以直接登录,登录之后需要先从文件导入城市信息,路线信息,然后根据菜单选择不同的功能。也可以修改密码。如果没有账号,就可以注册一个账号。
7.2 用户使用说明: 用户有账号可以直接登录,也可以修改密码,没有账号需要注册。登录账号之后,就可以选择相应的功能,例如查询最少花费路线,最少时间消耗路线。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<fstream>
#include<iomanip>
#include<queue>
#include<stack>
#include <graphics.h>
FILE* fq;
using namespace std;
#define INF 36726
char a[][20] = { "Train.txt","Flight.txt","TrainCity.txt","FlightCity.txt" };
char b[][10] = { "City","Line" };
typedef struct {
int day;
int hour;
int minute;
}Time;
typedef struct InforType {
char LineName[10];//航班号或火车车次
int LineType;//1 飞机 2火车
Time StartTime, EndTime;//航班或火车的出发时间和达到时间
Time SpendTime;//所用总时间
float Money;//票价
}TrafficLine;
typedef struct ArcNode {//边表
char EndName[10];
struct ArcNode* nextline;
TrafficLine* Info;//该边的路线信息
}LineNode;
typedef struct VNode {//顶点表
char CityName[10];//城市名
int CityOrder;//城市编号
LineNode* firstline;//指向第一个后继表的指针
int Amount;//该城市的总班次
}VNode, Vnode[50];
typedef struct {
Vnode CityList;//城市
int CityNum;//城市个数(顶点数)
int MaxCityNum;//当前最大城市个数
int ArcNum;//路线数(边数)
}ALGraph;
ALGraph G;
//输入时间-----------------------------------------------------------
void InputTime(TrafficLine& temp) {
char c1, c2, c3;
Time T0;
int day, hour, minute;
cout << "请输入出发时间(hh:mm,+d):";
cin >> hour >> c1 >> minute >> c2 >> c3 >> day;
T0.day = day;
T0.hour = hour;
T0.minute = minute;
temp.StartTime = T0;
Time T1;
cout << "请输入到达时间(hh:mm,+d):";
cin >> hour >> c1 >> minute >> c2 >> c3 >> day;
T1.day = day;
T1.hour = hour;
T1.minute = minute;
temp.EndTime = T1;
}
//计算所用时间函数-----------------------------------------------
void SpendTime(TrafficLine& temp) {
Time t;
t.day = 0;
t.hour = 0;
t.minute = 0;
t.minute = temp.EndTime.minute - temp.StartTime.minute;
if (t.minute < 0) {
t.minute += 60;
t.hour--;
}
t.hour = temp.EndTime.hour - temp.StartTime.hour;
if (t.hour < 0) {
t.hour += 24;
t.day--;
}
t.day = 0;
temp.SpendTime = t;
}
//输出时间函数-----------------------------------------------------------------
void Outputtime(Time t) {
//cout << setw(3) << t.hour << ":" << setw(2) << t.minute << setw(2) << t.day;
printf("\t%02d:%02d %d", t.hour, t.minute, t.day);
}// << "时间:" << endl
//查询城市编号----------------------------------------------------------
int SearchCityNum(char CityName[]) {
int i;
for (i = 0; i < G.CityNum; i++) {
if (strcmp(G.CityList[i].CityName, CityName) == 0)return i;//找到城市返回城市编号
}
return -1;//未找到城市
}
//手动添加城市-----------------------------------------------------------------
void AddCity(char Cityname[]) {
if (SearchCityNum(Cityname) != -1) {
//cout << "该城市在表中" << endl;
return;
}
G.MaxCityNum++;
strcpy(G.CityList[G.CityNum].CityName, Cityname);
// cout<<G.CityList[G.CityNum].CityName;
G.CityList[G.CityNum].CityOrder = G.CityNum;
// cout<<G.CityList[G.CityNum].CityOrder;
G.CityList[G.CityNum].firstline = NULL;
G.CityList[G.CityNum].Amount = 0;
G.CityNum++;
}
//从文件中读取添加城市---------------------------------------------------------------------
void AddCityFile(char FileName[]) {
cout << "从文件" << FileName << "读取信息!" << endl;
FILE* fp;
char str[10];
int count;
int a;
fp = fopen(FileName, "r");
if (fp == NULL) {
cout << "文件打开失败!" << endl;
return;
}
a = fscanf(fp, "%d\n", &count);
while (fscanf(fp, "%[^\n]%*c\n", str) != EOF)
{
AddCity(str);
}
cout << "城市导入完毕!" << endl;
fclose(fp);
}
//添加路线----------------------------------------------------------------------------------
void AddLine() {
void InsertLine(char Startcity[], char Endcity[], LineNode * temp);
char StartName[10], EndName[10];
//信息输入
cout << "请输入起点城市:" << endl;
cin >> StartName;
cout << "请输入终点城市:" << endl;
cin >> EndName;
LineNode* temp = new LineNode;
TrafficLine* info = new TrafficLine;
strcpy(temp->EndName, EndName);
cout << "请输入班次名:";
cin >> info->LineName;
InputTime(*info);
SpendTime(*info);
cout << "请输入票价:";
cin >> info->Money;
cout << "请输入类型:(1为飞机,2为火车)";
cin >> info->LineType;
temp->Info = info;
InsertLine(StartName, EndName, temp);
}//addLine
//插入线-------------------------------------------------------------------
void InsertLine(char Startcity[], char Endcity[], LineNode* temp) {
int StartNum, EndNum;
StartNum = SearchCityNum(Startcity);
EndNum = SearchCityNum(Endcity);
if (StartNum == -1) {
AddCity(Startcity); //若无城市,则新建
StartNum = SearchCityNum(Startcity);
}
if (SearchCityNum(Endcity) == -1) {
AddCity(Endcity); //若无城市,则新建
}
LineNode* p, * q;
p = G.CityList[StartNum].firstline;
if (p == NULL) { //起点城市原来没有路线的情况
G.CityList[StartNum].firstline = temp;
temp->nextline = NULL;
}
else {//原本有路的情况
q = p->nextline;
while (q != NULL && strcmp(Endcity, q->EndName) != 0) {
p = q;
q = q->nextline;
}
p->nextline = temp;
temp->nextline = q;
}
G.CityList[StartNum].Amount++;
G.ArcNum++;
}
//从文件插入路线-------------------------------------------------------------------
void AddLineFile(char FileName[]) {
cout << "从" << FileName << "中读取并导入线路!" << endl;
FILE* fp;
//int a=0;
fp = fopen(FileName, "r");
if (!fp) {
cout << "不能打开文件!" << endl;
return;
}
int hh = 0;//记录文件尾部位置
fseek(fp, 0, 2);
hh = ftell(fp);
fseek(fp, 0, 0);
char str[120];
char startname[10];
fgets(str, 120, fp);
while (hh != ftell(fp)) {
//if (feof(fp))break;
LineNode* temp = new LineNode;
TrafficLine* info = new TrafficLine;
memset(startname, '\0', sizeof(startname));
if (strcmp(FileName, "Train.txt") == 0) {
info->LineType = 2;
}//火车类型
else info->LineType = 1; //飞机类型
fscanf(fp, "%s%s%s%d:%d +%d %d:%d +%d %d:%d +%d %f", startname, temp->EndName, info->LineName, &info->StartTime.hour,
&info->StartTime.minute, &info->StartTime.day, &info->EndTime.hour, &info->EndTime.minute, &info->EndTime.day,
&info->SpendTime.hour, &info->SpendTime.minute, &info->SpendTime.day, &info->Money);
SpendTime(*info);//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
temp->Info = info;
//cout << a << endl;
InsertLine(startname, temp->EndName, temp);
}
//G.ArcNum--; //文件读入时到末尾还循环一次,多了一次
//G.CityNum--; //文件读入时到末尾还循环一次,多了一次
fclose(fp); //打开存储线路的文件完毕,关闭file
cout << "线路导入完毕!" << endl;
}
//删除序号为i的城市所有路线-------------------------------------------------------------------------
void DelCityLine(int i) {
LineNode* p, * q;
p = G.CityList[i].firstline;
if (p == NULL) {
return;//空表
}
//从第二个表结点开始删
while (p->nextline) {
q = p;
p = q->nextline;
delete q->Info;
delete q;
}
//删除最后一个结点
if (p->nextline == NULL) {
delete p->Info;
delete p;
}
}
//判断图中有火车路线的城市数量
int TrainNum()
{
int i;
int count = 0;
LineNode* p;
for (i = 0; i < G.CityNum; i++) {
p = G.CityList[i].firstline;
while (p != NULL) {
if (p->Info->LineType == 2) {
count++;
break;
}
else p = p->nextline;
}
}
return count;
}
//判断图中有飞机路线的城市数量
int FlightNum()
{
int i;
int count = 0;
LineNode* p;
for (i = 0; i < G.CityNum; i++) {
p = G.CityList[i].firstline;
while (p != NULL) {
if (p->Info->LineType == 1) {
count++;
break;
}
else p = p->nextline;
}
}
return count;
}
//删除以城市为节点的所有航班,火车路线
void DelCity(char CityName[]) {
int citynum = SearchCityNum(CityName);
int j;
if (citynum == -1) {
cout << "未查到城市信息!" << endl;
}
else {
DelCityLine(citynum);
for (j = citynum; j < G.CityNum - 1; j++) {
G.CityList[j] = G.CityList[j + 1];
}
G.CityNum--;
cout << "删除成功!" << endl;
}
}
//显示起点城市到终点城市所有路线信息-----------------------------------------------------------------
bool ShowLine(char startname[], char endname[]) {
int start, end;
bool flag = false;
start = SearchCityNum(startname);
end = SearchCityNum(endname);
LineNode* p;
for (p = G.CityList[start].firstline; p != NULL; p = p->nextline) {
if (strcmp(p->EndName, endname) == 0) {
cout << setw(8) << p->Info->LineName;
Outputtime(p->Info->StartTime);
Outputtime(p->Info->EndTime);
Outputtime(p->Info->SpendTime);
cout << setw(8) << p->Info->Money<<endl;
flag = true;
}
}
if (flag == false) {
cout << "没有从该城市出发的班次!" << endl;
}
return flag;
}
void ShowLine(int start, int end) {
LineNode* p;
for (p = G.CityList[start].firstline; p != NULL; p = p->nextline) {
if (strcmp(p->EndName, G.CityList[end].CityName) == 0) {
cout << setw(8) << p->Info->LineName;
Outputtime(p->Info->StartTime);
Outputtime(p->Info->EndTime);
Outputtime(p->Info->SpendTime);
cout << setw(8) << p->Info->Money << endl;
}
}
}
//显示系统中所有城市信息----------------------------------------------------------------------
void ShowCity() {
int i;
if (G.CityNum == 0) {
cout << "该系统还没有城市信息!" << endl;
}
else {
cout << "系统中有 " << G.CityNum << " 座城市的信息" << endl;
for (i = 0; i < G.CityNum; i++) {
cout << G.CityList[i].CityName << endl;
}
}
}
//显示系统中所有路线信息------------------------------------------------------------------------
void ShowLine() {
int i;
if (G.ArcNum == 0) {
cout << "该系统还没有城市路线信息!" << endl;
}
else {
cout << "系统中有 " << G.ArcNum << " 条线路的信息" << endl;
cout << "出发城市|到达城市|班次名||||||||出发时间||||||||到达时间||||||||||用时|||||||票价" << endl;
LineNode* p = NULL;
for (i = 0; i < G.CityNum; ++i) {
p = G.CityList[i].firstline;
while (p) {
cout << setw(8) << G.CityList[i].CityName << " " << setw(8) << p->EndName << " " << setw(6) << p->Info->LineName << " ";
Outputtime(p->Info->StartTime);
cout << " ";
Outputtime(p->Info->EndTime);
cout << " ";
Outputtime(p->Info->SpendTime);
cout << " " << setw(5) << p->Info->Money << endl;
p = p->nextline;
}
}
}
}
//删除路线-----------------------------------------------------------------------
void DelLine() {
LineNode* p, * q;
char startname[10], endname[10];
int startnum, endnum;
int flag=false;
cout << "请输入起点城市: ";
cin >> startname;
startnum = SearchCityNum(startname);
if (startnum == -1) {
cout << "没有该城市出发的线路!" << endl;
return;
}
cout << "请输入终点城市: ";
cin >> endname;
endnum = SearchCityNum(endname);
flag=ShowLine(startname, endname);
if (flag) {
char lineName[10];
cout << "请输入你想要删除的班次:" << endl;
cin >> lineName;
p = G.CityList[startnum].firstline;
q = p->nextline;//q 是 p 的后继
//只有一条路,即一个表结点的情况
if (q == NULL) {
if (strcmp(p->Info->LineName, lineName) != 0) { //唯一一条路不是通往目的地的情况
cout << "没有该班次!" << endl;
return;
}
else {
G.CityList[startnum].firstline = NULL; //注意原内存需要手动释放 q!!!!!!!!!!!!!!!!!
G.CityList[startnum].Amount--;
G.ArcNum--;
//删除内存
delete p->Info; //将通过指针p,将结构体里的结构体指针指向的内存释放
delete p; //通过p,将结构体的内存free掉
p = NULL; //置指针为NULL,防止野指针
return;
}
}//if(q == NULL)
//多个表结点的情况
while (strcmp(q->Info->LineName, lineName) != 0 && q->nextline) {
p = q;
q = q->nextline;
}
//跳出循环有两种可能 1.名字相等 2.到头了
//1.到头了的情况
if (strcmp(q->Info->LineName, lineName) != 0) {
cout << "没有班次!" << endl;
return;
}
//2.名字相等的情况
else {
p->nextline = q->nextline;
G.CityList[startnum].Amount--;
G.ArcNum--;
delete q->Info;
delete q;
return;
}
}
}
//保存数据到文件中-------------------------------------------------------------------
void UpdataFile(char FileName[], char type[]) {
FILE* fp;
int i, j;
int counttrain = 0;// 城市数
int countflight = 0;
LineNode* p;
LineNode* q;
fp = fopen(FileName, "w");
if (fp == NULL) {
cout << "不能打开文件" << FileName << endl;
return;
}
counttrain = TrainNum();
countflight = FlightNum();
if (strcmp(type, "City") == 0) {//保存城市++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
if (strcmp(FileName, "TrainCity.txt") == 0) {
fprintf(fp, "%d\n", counttrain);
for (j = 0; j < G.CityNum; j++) { //判断有火车经过的城市读入文件中
q = G.CityList[j].firstline;
while (q != NULL) {
if (q->Info->LineType == 2) {
fprintf(fp, "%s\n", G.CityList[j].CityName);
break;
}
else q = q->nextline;
}
} //判断有火车经过的城市读入文件中
}
else {
fprintf(fp, "%d\n", countflight);
for (j = 0; j < G.CityNum; j++) { //判断有飞机经过的城市读入文件中
q = G.CityList[j].firstline;
while (q != NULL) {
if (q->Info->LineType == 1) {
fprintf(fp, "%s\n", G.CityList[j].CityName);
break;
}
else q = q->nextline;
}
}
} //判断飞机经过的城市读入文件中
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
else if (strcmp(type, "Line") == 0) {//保存路线
if (strcmp(FileName, "Train.txt") == 0) {
fprintf(fp, "出发城市 - 到达城市 ------ 班次名------ 出发时间------到达时间-------------- 用时-----------------票价");
for (i = 0; i < G.CityNum; i++) {
p = G.CityList[i].firstline;
while (p != NULL) {
if (p->Info->LineType == 2) {
fprintf(fp, "\n%-20s%-15s%-15s %02d:%02d +%d\t%02d:%-02d +%-5d\t%02d:%-02d +%-5d\t%10.2f", G.CityList[i].CityName, p->EndName, p->Info->LineName, p->Info->StartTime.hour,
p->Info->StartTime.minute, p->Info->StartTime.day, p->Info->EndTime.hour, p->Info->EndTime.minute, p->Info->EndTime.day,
p->Info->SpendTime.hour, p->Info->SpendTime.minute, p->Info->SpendTime.day, p->Info->Money);
}
p = p->nextline;
}
}
}
else {
fprintf(fp, "出发城市 - 到达城市 ------ 班次名------ 出发时间------到达时间-------------- 用时-----------------票价");
for (i = 0; i < G.CityNum; i++) {
p = G.CityList[i].firstline;
while (p != NULL) {
if (p->Info->LineType == 1) {
fprintf(fp, "\n%-20s %-15s %-15s %02d:%02d +%d\t%02d:%-02d +%-5d\t%02d:%-02d +%-5d\t%10.2f", G.CityList[i].CityName, p->EndName, p->Info->LineName, p->Info->StartTime.hour,
p->Info->StartTime.minute, p->Info->StartTime.day, p->Info->EndTime.hour, p->Info->EndTime.minute, p->Info->EndTime.day,
p->Info->SpendTime.hour, p->Info->SpendTime.minute, p->Info->SpendTime.day, p->Info->Money);
}
p = p->nextline;
}
}
}
}
fclose(fp);
cout << "文件保存完成!" << endl;
}
//链栈------------------------------------------------------------------------------
typedef struct StackNode
{
int data;
struct StackNode* next;
}StackNode,*LinkStack;
//初始化
int InitStack(LinkStack& S) {
S = NULL;
return 1;
}
//入栈
int Push(LinkStack& S, int e) {
StackNode* p = new StackNode;
p->data = e;
p->next = S;
S = p;
return 1;
}
//出栈
int Pop(LinkStack& S, int& e) {
if (S == NULL)return -1;
e = S->data;
LinkStack p = S;
S = S->next;
delete p;
return 1;
}
//取栈顶元素
int GetTop(LinkStack S) {
if (S != NULL)return S->data;
}
//判空
bool Empty(LinkStack S) {
if (S == NULL)return true;
else return false;
}
//最少花费路径--------------------------------------------------------------------------
struct Node {
int id; //源顶点id
float money; //(费用)
friend bool operator < (struct Node a, struct Node b) {
return a.money > b.money;
}
};
//迪杰斯卡尔算法计算最少花费--------------------------------------------------------------
void Dijkstra_Money(int v0, int* parent, Node* dis) {
priority_queue<Node> q; //队列存储最短距离与索引的编号
//parent[]记录每个顶点的父亲结点
//dis[]记录源点到每个估算距离,最后更新为源点到所有顶点的最短距离
bool visited[50] = { false }; //判断下标对应的顶点是否算出最短路径
int i;
for (i = 0; i < G.CityNum; ++i) {//初始化
dis[i].id = i;
dis[i].money = INF;
parent[i] = -1; //每个顶点都没有父结点
visited[i] = false; //都未找到最短路
}
dis[v0].money = 0; //源点到源点最短路权值为0
q.push(dis[v0]); //压入队列
while (!q.empty()) { //队列空说明完成了求解v0到其余各顶点的最短路径
Node cd = q.top(); //取最小费用顶点
q.pop();
int u = cd.id;
if (visited[u]) { //被标记了,就无需对其进行更新最短距离等等操作
continue;
}
visited[u] = true;
LineNode* p = G.CityList[u].firstline;
//松弛操作
while (p) { //找所有与它相邻的顶点,进行松弛操作,更新估算费用,压入队列
int v = SearchCityNum(p->EndName);
float m = p->Info->Money;
if (!visited[v] && dis[v].money > dis[u].money + m) {
dis[v].money = dis[u].money + m;
parent[v] = u;
q.push(dis[v]);
}
p = p->nextline;
}
}// while (!q.empty())
}//dijkstra_Money
//中转次数最少-------------------------------------------------------------------
struct TranNode { //记录最少中转次数结构体
int id;
int count;
friend bool operator < (struct TranNode a, struct TranNode b) {
return a.count > b.count;
}
};
//迪杰斯卡尔算法计算最少中转--------------------------------------------------------------
void Dijkstra_Tran(int v0, int* parent, TranNode* dis) {
priority_queue<TranNode> q; //队列存储最少中转次数与索引的编号
//parent[]记录每个顶点的父亲结点
//dis[]记录源点到每个估算距离,最后更新为源点到所有顶点的最短距离
bool visited[50] = { false }; //判断下标对应的顶点是否算出最少中转次数
int i;
for (i = 0; i < G.CityNum; ++i) {//初始化
dis[i].id = i;
dis[i].count = INF;
parent[i] = -1; //每个顶点都没有父结点
visited[i] = false; //都未找到最短路
}
dis[v0].count = 0; //源点到源点最少中转次数为0
q.push(dis[v0]); //压入队列
while (!q.empty()) { //队列空说明完成了求解v0到其余各顶点的最少中转次数
TranNode cd = q.top(); //取最小中转次数顶点
q.pop();
int u = cd.id;
if (visited[u]) { //被标记了,就无需对其进行更新最少中转次数等等操作
continue;
}
visited[u] = true;
LineNode* p = G.CityList[u].firstline;
//松弛操作
while (p) { //找所有与它相邻的顶点,进行松弛操作,更新中转次数,压入队列
int v = SearchCityNum(p->EndName);
if (!visited[v] && dis[v].count > dis[u].count) {
dis[v].count = ++dis[u].count;
parent[v] = u;
q.push(dis[v]);
}
p = p->nextline;
}
}// while (!q.empty())
}//dijkstra_Tran
//最少时间路径------------------------------------------------------------------------------
struct Node1 {
int id; //源顶点id
int tt; //(时间)
Time et; //到达时间
friend bool operator < (struct Node1 a, struct Node1 b) {
return a.tt > b.tt;
}
};
int TimeTransWeight(const Time& t1, const Time& t2) {
Time t;
t.day = 0;
t.hour = 0;
t.minute = 0;
t.minute = t1.minute - t2.minute;
if (t.minute < 0) {
t.minute += 60;
t.hour--;
}
t.hour = t1.hour - t2.hour;
if (t.hour < 0) {
t.hour += 24;
t.day--;
}
if (t1.day < t2.day) {
t.day++;
}
return t.hour * 60 + t.minute;
}
int TimeWeight(const Time& t) {
return (t.day * 24 + t.hour) * 60 + t.minute;
}
void Dijkstra_Time(int v0, int* parent, Node1* dis) {
priority_queue<Node1> q1;
//dis[]记录源点到每个估算距离,最后更新为源点到所有顶点的最短距离
bool visited[50] = { false }; //判断下标对应的顶点是否算出最短路径
int i;
for (i = 0; i < G.CityNum; ++i) {
dis[i].id = i;
dis[i].tt = INF;
dis[i].et.day = 0;
dis[i].et.hour = 0;
dis[i].et.minute = 0;
parent[i] = -1; //都一个顶点都没有父结点
visited[i] = false; //都未找到最短路径
}
dis[v0].tt = 0;
q1.push(dis[v0]);
while (!q1.empty()) {
Node1 cd = q1.top(); //取出最短距离的点的序号
q1.pop();
int u = cd.id;
if (visited[u]) {
continue;
}
visited[u] = true;
LineNode* p = G.CityList[u].firstline;
//找出所有相邻点,进行松弛操作,即更新dis
while (p) {
int v = SearchCityNum(p->EndName);
int t = TimeWeight(p->Info->SpendTime);
Time st = p->Info->StartTime; //本条线路开始时间
//计算中转的时间开销
if (u != v0) { //注意源点到任何点都没有中转时间
int change = TimeTransWeight(st, dis[u].et); //当前路线的开车时间-始发站的上一到站时间
t += change;
}
if (!visited[v] && dis[v].tt > dis[u].tt + t) {
dis[v].tt = dis[u].tt + t;
dis[v].et = p->Info->EndTime;
parent[v] = u;
q1.push(dis[v]);
}
p = p->nextline;
}//while (p)
}//while (!q1.empty())
}//Dijkstra_Time
//最短路径----------------------------------------------------------------------------
void ShowShortestPath(const char type[]) {
char StartCity[10], EndCity[10];
int StartNum, EndNum;
int topdata;
//确定出发城市
ShowCity();
cout << "城市列表如上,请输入出发城市:";
cin >> StartCity;
StartNum = SearchCityNum(StartCity);
//输入城市不存在
while (StartNum == -1) {
cout << "查询不到该城市,请再次输入出发城市:" << endl;
cin >> StartCity;
StartNum = SearchCityNum(StartCity);
}
//确定到达目的城市
// ShowCity();
cout << "请输入目的城市:";
cin >> EndCity;
EndNum = SearchCityNum(EndCity);
//输入城市不存在
while (EndNum == -1) {
cout << "查询不到该城市,请再次输入目的城市:" << endl;
cin >> EndCity;
EndNum = SearchCityNum(EndCity);
}
int path[50]; //记录每个顶点的父亲结点,相当于是一条路径
int time_minute = 0; //起始地到达目的地的最少时间, 单位:分钟
float money_yuan = 0; //起始地到达目的地的最少费用,单位:元
int trancount = 0;//起始地到达目的地的最少中转次数
if (strcmp(type, "Money") == 0) {
Node dis[50];
Dijkstra_Money(StartNum, path, dis);
money_yuan = dis[EndNum].money;
}
else if (strcmp(type, "Time") == 0) {
Node1 dis[50];
Dijkstra_Time(StartNum, path, dis);
time_minute = dis[EndNum].tt;
}
else {
TranNode dis[50];
Dijkstra_Tran(StartNum, path, dis);
trancount = dis[EndNum].count;
}
//若v0 到 EndCity 不存在路,即EndCity 在最短路径树中没有父结点
if (path[EndNum] == -1) {
cout << "对不起,从" << StartCity << "到" << EndCity << "暂时没有路线到达!" << endl;
return;
}
else {
LinkStack S;
InitStack(S);
int step = EndNum;
while (step != StartNum) {
Push(S, step);
step = path[step];
}
int father = StartNum;//step
int child;
//输出最省钱路径
if (strcmp(type, "Money") == 0) {
cout << "最省钱路径" << endl;
int tt = 0; //total time,总时间开销
Time et = { 0,0,0 };
while (!Empty(S)) {
child = GetTop(S);
Pop(S, topdata);
LineNode* p = G.CityList[father].firstline;
float mm = INF; //min money,当前记录到的最少金钱,不是总金钱
int i = 0;
int count; //记录指针移动的次数,方便定位
while (p) {
if (strcmp(p->EndName, G.CityList[child].CityName) == 0 && mm >= p->Info->Money) {
mm = p->Info->Money;
count = i;
}
p = p->nextline;
++i;
}
p = G.CityList[father].firstline;
i = 0;
while (i != count) {
p = p->nextline;
++i;
}
tt += TimeWeight(p->Info->SpendTime);
if (father != StartNum) {
tt = tt + TimeTransWeight(p->Info->StartTime, et);
cout << "需要中转等待 " << TimeTransWeight(p->Info->StartTime, et) << "分钟!" << endl;
}
cout << setw(8) << G.CityList[father].CityName << " " << setw(8) << p->EndName << " " << setw(6) << p->Info->LineName << " ";
Outputtime(p->Info->StartTime);
Outputtime(p->Info->EndTime);
Outputtime(p->Info->SpendTime);
cout << " " << p->Info->Money << endl;
et = p->Info->EndTime;
father = child;
}//while(!s.empty())
cout << "一共花费" << money_yuan << "元和" << tt << "分钟!" << endl;
}//输出最省钱路径
//输出最省时间的路径
else if (strcmp(type, "Time") == 0) {
cout << "最省时间路径: " << endl;
float mm = 0; //总共需要的金钱
Time et = { 0, 0, 0 };
while (!Empty(S)) {
child = GetTop(S);
Pop(S, topdata);
LineNode* p = G.CityList[father].firstline;
int tt = INF; //当前记录到的最小时间,不是总时间
int ot = 0; //ot 是算上换乘的总时间
int i = 0, count = 0; //count记录指针移动的次数,方便定位
while (p) {
if (strcmp(p->EndName, G.CityList[child].CityName) == 0) {
if (!Empty(S) && child != EndNum) {
ot = TimeWeight(p->Info->SpendTime) + TimeTransWeight(p->Info->StartTime, et);
}
else {
ot = TimeWeight(p->Info->SpendTime);
}
if (tt >= ot) {
tt = ot;
count = i;
}
}
p = p->nextline;
++i;
}//while (p)
p = G.CityList[father].firstline;
i = 0;
while (i != count) {
p = p->nextline;
mm += p->Info->Money;
++i;
}
if (p != NULL) {
if (father != StartNum) {
cout << "需要中转等待 " << TimeTransWeight(p->Info->StartTime, et) << "分钟!" << endl;
}
cout << setw(8) << G.CityList[father].CityName << " " << setw(8) << p->EndName << " " << setw(6) << p->Info->LineName << " ";
Outputtime(p->Info->StartTime);
Outputtime(p->Info->EndTime);
Outputtime(p->Info->SpendTime);
cout << " " << p->Info->Money << endl;
et = p->Info->EndTime;
father = child;
}
}//while(!s.empty())
cout << "一共花费" << mm << "元和" << time_minute << "分钟!" << endl;
}//输出最省时间的路径
else { //输出最少中转次数路径
cout << "最少中转次数需要经历的城市:";
Push(S,StartNum);
while (!Empty(S)) {
cout << setw(5) << G.CityList[GetTop(S)].CityName;
Pop(S, topdata);
}
cout << endl;
step = EndNum; //将需要经过的城市入栈
while (step != StartNum) {
Push(S,step);
step = path[step];
}
Push(S,StartNum);
while (!Empty(S)) {
father = GetTop(S);
Pop(S,topdata);
if (!Empty(S)) {
child = GetTop(S);
cout << setw(5) << G.CityList[father].CityName << setw(5) << G.CityList[child].CityName << endl;
ShowLine(father, child);
}
}
}//while(!s.empty())
}//有路径
}//showShortestPath
int nUserNum = 0;//注册的用户编号(从0开始)(同时也代表着注册人数)
int nAdminiNum = 0;//注册的管理员编号 (第一个注册的用户编号为0)
int nUserFlag = 0;//定义判断用户是否登录的标志变量
int nAdminiFlag = 0;//定义判断管理员是否登录的标志变量
int usernum;//定义登录的用户编号
int admininum;//定义登录的管理员编号
struct user
{
char szName[20];//定义用户名
char password1[20];//定义用户账户密码
char password2[20];//定义用户二次输入密码
int nSerialNum;//定义用户序号(从1开始)
}user[10];
//定义管理员的结构体数组
struct admini
{
char szName[20];//定义管理员用户名
char password1[20];//定义管理员账户密码
char password2[20];//定义管理员二次输入密码
int nSerialNum;//定义管理员序号(从1开始)
}admini[10];
void SaveFile(FILE* fp)
{
fopen_s(&fp, "alldate.dat", "wb");
//向文件输出全局变量
fwrite(&nUserNum, 4, 1, fp);
fwrite(&nAdminiNum, 4, 1, fp);
fwrite(&nUserFlag, 4, 1, fp);
fwrite(&nAdminiFlag, 4, 1, fp);
fwrite(&usernum, 4, 1, fp);
fwrite(&admininum, 4, 1, fp);
//输出学生结构体数据
for (int i = 0; i < nUserNum; i++)
fwrite(&user[i], sizeof(struct user), 1, fp);
//输出教师结构体数组
for (int i = 0; i < nAdminiNum; i++)
fwrite(&admini[i], sizeof(struct admini), 1, fp);
fclose(fp);
}
void ReadFile(FILE* fp)
{
fopen_s(&fp, "alldate.dat", "rb");
//向文件输出全局变量
fread(&nUserNum, 4, 1, fp);
fread(&nAdminiNum, 4, 1, fp);
fread(&nUserFlag, 4, 1, fp);
fread(&nAdminiFlag, 4, 1, fp);
fread(&usernum, 4, 1, fp);
fread(&admininum, 4, 1, fp);
//输出学生结构体数据
for (int i = 0; i < nUserNum; i++)
fread(&user[i], sizeof(struct user), 1, fp);
//输出教师结构体数组
for (int i = 0; i < nAdminiNum; i++)
fread(&admini[i], sizeof(struct admini), 1, fp);
fclose(fp);
}
void User_Register(FILE* fp)
{
int i;
do {
cout << "请输入用户名:";
cin >> user[nUserNum].szName;
//接下来查找用户信息表中的内容,比较新输入的用户名是否存在,如果存在,系统给出提示
for (i = 0; i < nUserNum; i++)
{
if (strcmp(user[i].szName, user[nUserNum].szName) == 0)
{
cout<<"该用户已经存在,请重新输入:";//输出提示,提醒用户
break;//跳出for循环
}
}
if (i >= nUserNum)//说明没有找到重复的用户名
break;
} while (1);//如果用户名重复则一直循环,直到不重复时跳出循环
//输入用户名函数结束
/*下面设置用户密码*/
do {
//提示用户输入密码
cout << "请设置密码:";
cin >> user[nUserNum].password1;
cout << "请确认密码";
cin>>user[nUserNum].password2;//提示用户确认密码
if (strcmp(user[nUserNum].password1, user[nUserNum].password2) != 0)//两次输入密码不相等
cout<<"两次输入不一致,请重新输入";
else
{
cout<<"注册成功!"<<endl;
nUserNum++;//代表下一个将要注册的学生用户的编号
//user[nUserNum - 1].nSerialNum = nUserNum;//加一
SaveFile(fp);//调用文件保存函数
break;
}
} while (1);
}
//用户登录
void User_Logon()
{
int i;
char username[20];//定义一个临时存储用户名的字符数组
char password[20];//定义一个临时存储密码的字符数组
do {
cout << "请输入用户名:";
cin >> username;
//提示用户输入用户名,输入给临时存储用户名的字符数组
for (i = 0; i < nUserNum; i++)
if (strcmp(username, user[i].szName) == 0)//找到了
{
usernum = i;
break;//跳出for循环
}//记录输入用户名所对应的学生编号,即登录的用户所对应的编号
if (i >= nUserNum)//说明没有找到对应用户名
cout<<"该用户不存在"<<endl;
else
break;//找到了此用户名,退出输入用户名的循环,进入输入密码模块
} while (1);
/*输入密码模块*/
do {
cout << "请输入密码:";
cin>>password;//提示用户输入密码,输入给临时存储密码的字符数组
if (strcmp(password, user[usernum].password1) == 0)//密码符合
{
cout<<"登录成功!"<<endl;
nUserFlag = 1;//标志着已经成功登录
break;
}//结束密码输入模块
else
cout<<"密码错误"<<endl;
} while (1);
}
//用户修改密码
void User_ResetPassword(FILE* fp)
{
//studentnum 记录修改密码的学生用户的编号(即登录的学生用户的编号)
int i;
char username[20];//定义一个临时存储用户名的字符数组
char password[20];//定义一个临时存储密码的字符数组
char resetpassword[20];//定义一个临时存储修改后密码的字符数组
do {
cout << "请输入用户名:";//提示用户输入用户名,输入给临时存储用户名的字符数组
cin >> username;
for (i = 0; i < nUserNum; i++)
if (strcmp(username, user[i].szName) == 0)//找到了
{
usernum = i;
break;
}//记录登录的用户所对应的编号
if (i >= nUserNum)//说明没有找到对应用户名
cout<<"该用户不存在"<<endl;
else
break;//找到了此用户名,退出输入用户名的循环,进入修改密码模块
} while (1);
do {
cout << "请输入原始密码:";
cin>>password;
if (strcmp(password, user[usernum].password1) == 0)//密码符合
{
cout << "密码正确,请输入修改密码:";
cin >> resetpassword;
strcpy(user[usernum].password1, resetpassword);//将原密码改为修改后的密码(wcscpy相当于strcopy)
cout<<"修改密码成功!"<<endl;
SaveFile(fp);//调用文件保存函数
break;//退出修改密码模块
}
else
cout<<"密码错误"<<endl;
} while (1);
}
//管理员创建账户
void Admini_Register(FILE* fp)
{
int i;
do {
cout << "请输入用户名:"; //提示用户输入用户名
cin >> admini[nAdminiNum].szName;
//接下来查找用户信息表中的内容,比较新输入的用户名是否存在,如果存在,系统给出提示
for (i = 0; i < nAdminiNum; i++)
{
if (strcmp(admini[i].szName, admini[nAdminiNum].szName) == 0)
{
cout<<"该用户已经存在,请重新输入";//输出提示,提醒用户
break;//跳出for循环
}
}
if (i >= nAdminiNum)//说明没有找到与已注册用户重复的用户名
break;
} while (1);//如果用户名重复则一直循环,直到不重复时跳出循环
//输入用户名函数结束
/*下面设置用户密码*/
do {
cout << "请设置密码:";//提示用户输入密码
cin >> admini[nAdminiNum].password1;
cout << "请确认密码:"; //提示用户确认密码
cin >> admini[nAdminiNum].password2;
if (strcmp(admini[nAdminiNum].password1, admini[nAdminiNum].password2) != 0)//两次输入密码不相等
cout<<"两次输入不一致,请重新输入:";
else
{
cout << "注册成功!"<<endl;
nAdminiNum++;//表示下一次将要注册的教师用户的编号
SaveFile(fp);//调用文件保存函数
break;
}
} while (1);
}
//管理员登录
void Admini_Logon()
{
int i;
char username[20];//定义一个临时存储管理员名的字符数组
char password[20];//定义一个临时存储密码的字符数组
do {
cout << "请输入用户名:";//提示用户输入管理员名,输入给临时存储管理员名的字符数组
cin >> username;
for (i = 0; i < nAdminiNum; i++)
if (strcmp(username, admini[i].szName) == 0)//找到了
{
admininum = i;
break;
}//记录输入管理员名所对应的编号
if (i >= nAdminiNum)//说明没有找到对应管理员名
cout<<"该用户不存在"<<endl;
else
break;//找到了此管理员名,退出输入管理员的循环,进入输入密码模块
} while (1);
/*输入密码模块*/
do {
cout << "请输入密码:";
cin >> password;//提示管理员输入密码,输入给临时存储密码的字符数组
if (strcmp(password, admini[admininum].password1) == 0)//密码符合
{
cout<<"登录成功!"<<endl;
nAdminiFlag = 1;//标志管理员登录成功
break;
}//结束密码输入模块
else
cout<<"密码错误"<<endl;
} while (1);
}
//管理员修改密码
void Admini_ResetPassword(FILE* fp)
{
//admininum 记录修改密码的管理员的编号
int i;
char username[20];//定义一个临时存储管理员名的字符数组
char password[20];//定义一个临时存储密码的字符数组
char resetpassword[20];//定义一个临时存储修改后密码的字符数组
do {
cout << "请输入用户名:";
cin >> username;
for (i = 0; i < nAdminiNum; i++)
if (strcmp(username, admini[i].szName) == 0)//找到了
{
admininum = i;
break;
}//记录输入管理员名所对应的管理员编号,即登录的管理员所对应的编号
if (i >= nAdminiNum)//说明没有找到对应管理员名
cout<<"该用户不存在";
else
break;//找到了此用户名,退出输入管理员名的循环,进入修改密码模块
} while (1);
do {
cout << "请输入原始密码:";
cin>>password;
if (strcmp(password, admini[admininum].password1) == 0)//密码符合
{
cout << "密码正确,请输入修改密码:";
cin >> resetpassword;
strcpy(admini[admininum].password1, resetpassword);//将原密码改为修改后的密码
cout << "修改密码成功!" << endl;
SaveFile(fp);//调用文件保存函数
break;//退出修改密码模块
}
else
cout << "密码错误" << endl;
} while (1);
}
void SencondUser_Meau();
void user_Meau();
void admini_Meau();
void Sencondadmini_Meau();
void FirstMeau() {
ReadFile(fq);
while (1) {
cout << "---------------------------------------------------------" << endl;
cout << "|\t\t\t\t\t\t\t|" << endl;
cout << "|\t********************************\t\t|" << endl;
cout << "|\t\t\t\t\t\t\t|" << endl;
cout << "|\t 欢迎来到全国交通资讯系统\t\t\t|" << endl;
cout << "|\t\t\t\t\t\t\t|" << endl;
cout << "|\t********************************\t\t|" << endl;
cout << "|\t\t\t\t\t\t\t|" << endl;
cout << "|\t\t\t\t\t\t\t|" << endl;
cout << "|\t\t\t\t\t\t\t|" << endl;
cout << "| 1.管理员界面\t\t\t\t2.用户界面\t|" << endl;
cout << "|\t\t\t\t\t\t\t|" << endl;
cout << "|\t\t\t\t\t\t\t|" << endl;
cout << "---------------------------------------------------------" << endl;
cout << "请输入您的选择:" << endl;
int choose;
cin >> choose;
if (choose == 1)admini_Meau();
else user_Meau();
Sleep(800);
system("cls");
}
}
void user_Meau() {
Sleep(800);
system("cls");
while (1) {
cout << "------------------------------------------------------------------" << endl;
cout << "|\t\t\t\t\t\t\t\t|" << endl;
cout << "|\t\t************用户界面*************\t\t|" << endl;
cout << "|\t\t\t\t\t\t\t\t|" << endl;
cout << "|\t\t\t\t\t\t\t\t|" << endl;
cout << "|\t\t\t1.注册账户\t\t\t\t|" << endl;
cout << "|\t\t\t2.登录账户\t\t\t\t|" << endl;
cout << "|\t\t\t3.修改密码\t\t\t\t|" << endl;
cout << "|\t\t\t4.后退 \t\t\t\t|" << endl;
cout << "|\t\t\t\t\t\t\t\t|" << endl;
cout << "-----------------------------------------------------------------" << endl;
cout << "请输入您的选择:" << endl;
int choose;
cin >> choose;
if (choose == 1)User_Register(fq);
else if (choose == 2) {
User_Logon();
if (nUserFlag == 1)SencondUser_Meau();
}
else if (choose == 3) User_ResetPassword(fq);
else break;
Sleep(800);
system("cls");
}
}
//system("cls");
void admini_Meau() {
Sleep(800);
system("cls");
while (1) {
cout << "-----------------------------------------------------------------" << endl;
cout << "|\t\t\t\t\t\t\t\t|" << endl;
cout << "|\t\t************管理员界面*************\t\t|" << endl;
cout << "|\t\t\t\t\t\t\t\t|" << endl;
cout << "|\t\t\t\t\t\t\t\t|" << endl;
cout << "|\t\t\t1.注册账户\t\t\t\t|" << endl;
cout << "|\t\t\t2.登录账户\t\t\t\t|" << endl;
cout << "|\t\t\t3.修改密码\t\t\t\t|" << endl;
cout << "|\t\t\t4.后退 \t\t\t\t|" << endl;
cout << "|\t\t\t\t\t\t\t\t|" << endl;
cout << "-----------------------------------------------------------------" << endl;
cout << "请输入您的选择:" << endl;
int choose;
cin >> choose;
if (choose == 1)Admini_Register(fq);
else if (choose == 2) {
Admini_Logon();
if (nAdminiFlag == 1) Sencondadmini_Meau();
}
else if (choose == 3) Admini_ResetPassword(fq);
else break;
Sleep(800);
system("cls");
}
}
void Sencondadmini_Meau() {
Sleep(800);
system("cls");
char cityname[10];
int flag = 0;
while (1) {
flag = 0;
cout << "---------------------------------------------------------" << endl;
cout << "|\t\t\t\t\t\t\t|" << endl;
cout << "|\t\t\t\t\t\t\t|" << endl;
cout << "|\t\t1.添加城市 \t\t|" << endl;
cout << "|\t\t\t\t\t\t\t|" << endl;
cout << "|\t\t2.删除城市 \t\t|" << endl;
cout << "|\t\t\t\t\t\t\t|" << endl;
cout << "|\t\t3.查看所有城市 \t\t|" << endl;
cout << "|\t\t\t\t\t\t\t|" << endl;
cout << "|\t\t4.删除两个城市之间的路线 \t\t|" << endl;
cout << "|\t\t\t\t\t\t\t|" << endl;
cout << "|\t\t5.查看所有路线 \t\t|" << endl;
cout << "|\t\t\t\t\t\t\t|" << endl;
cout << "|\t\t6.添加路线 \t\t|" << endl;
cout << "|\t\t\t\t\t\t\t|" << endl;
cout << "|\t\t7.保存文件 \t\t|" << endl;
cout << "|\t\t\t\t\t\t\t|" << endl;
cout << "|\t\t8.后退 \t\t|" << endl;
cout << "|\t\t\t\t\t\t\t|" << endl;
cout << "---------------------------------------------------------" << endl;
cout << "请输入您的选择:" << endl;
int choose = 0;
int w = 0;
cin >> choose;
switch (choose) {
case 1:
cout << "1.手动添加\t\t2.从文件添加" << endl << "输入你的选择:";
cin >> w;
if (w == 1) {
cout << "输入需要添加的城市名:";
cin >> cityname;
AddCity(cityname);
}
else {
AddCityFile(a[2]);
AddCityFile(a[3]);
}
break;
case 2:
cout << "输入需要删除的城市名:";
cin >> cityname;
DelCity(cityname);
break;
case 3:
ShowCity();
break;
case 4:
DelLine();
break;
case 5:
ShowLine();
break;
case 6:
cout << "1.手动添加\t\t2.从文件添加" << endl << "输入你的选择:";
cin >> w;
if (w == 1)
AddLine();
else {
AddLineFile(a[0]);
AddLineFile(a[1]);
}
break;
case 7:
UpdataFile(a[0],b[1]);
UpdataFile(a[1], b[1]);
UpdataFile(a[2], b[0]);
UpdataFile(a[3], b[0]);
break;
case 8:
flag=1;
break;
}
if (flag == 1) {
Sleep(800);
system("cls");
break;
}
}
}
void SencondUser_Meau( )
{
Sleep(800);
system("cls");
AddLineFile(a[0]);
AddLineFile(a[1]);
AddCityFile(a[2]);
AddCityFile(a[3]);
while (1) {
cout << "---------------------------------------------------------" << endl;
cout << "|\t\t\t\t\t\t\t|" << endl;
cout << "|\t\t\t\t\t\t\t|" << endl;
cout << "|\t\t1.查询两个城市之间的路线\t\t|" << endl;
cout << "|\t\t\t\t\t\t\t|" << endl;
cout << "|\t\t2.查询时间最少路线 \t\t|" << endl;
cout << "|\t\t\t\t\t\t\t|" << endl;
cout << "|\t\t3.查询费用最少路线 \t\t|" << endl;
cout << "|\t\t\t\t\t\t\t|" << endl;
cout << "|\t\t4.查询中转次数最少方案 \t\t|" << endl;
cout << "|\t\t\t\t\t\t\t|" << endl;
cout << "|\t\t5.后退 \t\t|" << endl;
cout << "|\t\t\t\t\t\t\t|" << endl;
cout << "|\t\t\t\t\t\t\t|" << endl;
cout << "---------------------------------------------------------" << endl;
cout << "请输入您的选择:" << endl;
int choose;
cin >> choose;
if (choose == 1) {
char aa[10], bb[10];
cout << "输入需要查询的起点城市:";
cin >> aa;
cout << "输入需要查询的终点城市:";
cin >> bb;
cout << "||||班次名||||出发时间||||||||到达时间||||||||||用时||||||||||票价" << endl;
ShowLine(aa, bb);
}
else if (choose == 2)ShowShortestPath("Time");
else if (choose == 3)ShowShortestPath("Money");
else if (choose == 4) ShowShortestPath("Tran");
else {
Sleep(800);
system("cls");
break;
}
}
}
int main() {
FirstMeau();
return 0;
}
最后,整理不易,希望看到的朋友点个赞,给个关注!