全国交通资讯系统

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); //打开存储线路的文件完毕,关闭filecout << "线路导入完毕!" << 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;    //源顶点idfloat 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; //源点到源点最短路权值为0q.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; //源点到源点最少中转次数为0q.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; //源顶点idint 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;//找出所有相邻点,进行松弛操作,即更新diswhile (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;//stepint 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;elsebreak;//找到了此用户名,退出输入用户名的循环,进入输入密码模块 } while (1);/*输入密码模块*/do {cout << "请输入密码:";cin>>password;//提示用户输入密码,输入给临时存储密码的字符数组if (strcmp(password, user[usernum].password1) == 0)//密码符合 {cout<<"登录成功!"<<endl;nUserFlag = 1;//标志着已经成功登录 break;}//结束密码输入模块 elsecout<<"密码错误"<<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;elsebreak;//找到了此用户名,退出输入用户名的循环,进入修改密码模块 } 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;//退出修改密码模块 }elsecout<<"密码错误"<<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;elsebreak;//找到了此管理员名,退出输入管理员的循环,进入输入密码模块 } while (1);/*输入密码模块*/do {cout << "请输入密码:";cin >> password;//提示管理员输入密码,输入给临时存储密码的字符数组if (strcmp(password, admini[admininum].password1) == 0)//密码符合 {cout<<"登录成功!"<<endl;nAdminiFlag = 1;//标志管理员登录成功 break;}//结束密码输入模块 elsecout<<"密码错误"<<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<<"该用户不存在";elsebreak;//找到了此用户名,退出输入管理员名的循环,进入修改密码模块 } 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;//退出修改密码模块 }elsecout << "密码错误" << 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;
}

最后,整理不易,希望看到的朋友点个赞,给个关注!