全国交通资讯系统

全国交通资讯系统

1. 题目

1.1 问题描述 设计、实现一个全国大城市间的交通咨询程序,为旅客提供三种最优决策方案: (1)时间最短 (2)费用最小 (3)中转次数最少。
1.2 实现提示
该程序所做的工作的是模拟全国交通咨询,为旅客提供三种最优决策的交通咨询。 (1)在程序中输入城市名称时,需输入10个字母以内的字母串;输入列车或飞机编号时需输入一个整型数据;输入列车或飞机的费用时需输入一个实型数据;输入列车或飞机开始时间和到达时间时均需输入两个整型数据(以hh:mm的形式);在选择功能时,应输入与所选功能对应的一个整型数据。
(2)程序的输出信息主要是:最快需要多少时间才能到达,或最少需要多少旅费才能到达,或最少需要多少次中转到达,并详细说明依次于何时乘坐哪一趟列车或哪一次班机到何地。
(3)程序的功能包括:提供对城市信息的编辑,提供列车时刻表和飞机航班表的编辑,提供三种最优决策:最快到达、最省钱到达、最少中转次数到达。
测试数据:

航班时刻表:

出发城市到达城市班次名出发时间到达时间用时票价
北京上海MU632016:20 +017:25 +001:5 +0680.00
北京乌鲁木齐CA210408:00 +009:55 +001:55 +01150.00
北京西安MC20115:25 +017:0 +002:35 +0930.00
西安北京MC20112:35 +014:15 +002:40 +0930.00
西安广州CM232307:15 +009:35 +002:20 +01320.00
上海北京MU632018:00 +019:5 +001:5 +0680.00
广州西安CM232310:15 +011:35 +001:20 +01320.00
广州武汉CM472311:25 +013:5 +002:40 +0810.00
昆明拉萨MA17312:35 +014:0 +002:25 +0830.00
昆明乌鲁木齐CA8213:05 +015:50 +002:45 01480.00
武汉拉萨MC330416:25 +017:55 +001:30 +0890.00
武汉广州CM472307:05 +008:45 +001:40 +0810.00
乌鲁木齐北京CA210410:45 +011:40 +001:55 +01150.00
乌鲁木齐昆明CA8209:30 +012:15 +003:45 +01480.00
拉萨昆明MA17310:20 +011:45 +001:25 +0830.00
拉萨武汉MC330414:15 +015:45 +001:30 +0890.00

列车时刻表:

出发城市到达城市班次名出发时间到达时间用时票价
北京郑州K2713:15 +021:12 +008:57 +078.00
北京郑州T4107:11 +015:8 +008:57 +090.00
北京兰州T13419:24 +010:28 +115:4 +0162.00
郑州西安T2721:24 +005:13 +108:49 +082.00
郑州北京K2713:42 +021:40 +008:58 +078.00
郑州北京T4109:40 +017:37 +008:57 +090.00
郑州上海K4115:20 +000:13 +109:53 +0100.00
西安郑州T2705:41 +013:30 +008:49 +082.00
西安武汉K21801:34 +018:35 +017:1 +0178.00
上海郑州K4100:35 +009:28 +009:53 +0100.00
上海广州K5908:20 +003:16 +119:56 +0182.00
广州上海K5903:39 +022:53 +019:14 +0182.00
广州昆明K32306:18 +016:14 +010:56 +0102.00
广州长沙T37300:35 +011:35 +011:0 +0116.00
兰州北京T13403:52 +018:56 +015:4 +0162.00
兰州武汉K74717:41 +014:47 +121:6 +0210.00
兰州乌鲁木齐T37111:42 +023:54 +012:12 +0114.00
昆明广州K32316:31 +002:27 +110:56 +0102.00
昆明武汉T87321:42 +011:46 +114:4 +0134.00
武汉昆明T87307:13 +021:17 +014:4 +0134.00
武汉长沙K11609:36 +018:32 +009:56 +098.00
武汉兰州K74715:13 +012:19 +121:6 +0210.00
武汉西安K21818:50 +011:51 +117:1 +0178.00
长沙武汉K11618:54 +003:48 +109:54 +098.00
长沙广州T37313:15 +000:15 +111:0 +0116.00
乌鲁木齐兰州T37100:35 +011:23 +011:48 +0114.00
安徽郑州T55515:20 +020:35 +005:15 +0310.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;
}



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

  • 44
    点赞
  • 128
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@别样

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值