一,设计目标:
1.1.1对于管理员:
1>管理列车和站点的基本信息,包括增,删,查,改;
2>时间调度管理,对一特定车次增,删,查,改某一指定站点的列车行车信息。
1.1.2对于用户:
1>按出发站和到达站两站点查询列车;
2>按出发站和到达站两站点及出发时间查询列车;
3>按出发站和到达站两站点及到达时间查询列车;
具体要求:
1.2.1建立2个数据文件(站点station.txt、车次train.txt);
1.2.2要有3个数据类:
1>列车信息Information(含车次train_number、站点station、到达时间t1、开车时间t2,时间表示为时、分);
2>站点Station(含站点名称name、经过的车次向量(元素为列车信息);
3>车次train_number(含车次编号number、始发站、终点站、经过的站点向量(元素为列车信息));
1.2.3 要有2个操作类:
1>后台管理类AdminOp
数据成员:站点向量、车次向量;
实现功能:站点基本信息管理、车次基本信息管理、查询车次/站点信息、时间调度管理(按车次安排站点时间、修改站点时间、删除/增加站点,对应的站点对象的信息也要做相应的改变)
2>客户操作类ClientOp
数据成员:站点向量、车次向量;
实现功能:
站点信息查询:查询指定站点所经过的车次信息;
车次信息查询:查询指定车次所经过的站点信息;
基本查询:(输入起始、目的地站,查看相关的车次信息)依次从起始站点取出经过该站的车次,到目的地站对象中查找相应的车次信息,找到即显示。继续直到起始站所有车次处理完;
带时间限定的查询:分为起始站发车时间限定查询和目的地到达时间限定查询
中间换乘查询(选做):对于不能直接到达的基本查询,选取一个中间站点找到两个接力的车次以完成旅行。
1.2.4测试要求:
用3个不同的操作类对象运行管理端程序(与客户端程序间隔运行),完成对车次、站点信息的增删查改操作、时间调度管理。在数据文件中要有所反映;
分别定义3个客户端对象,在运行完管理端操作后运行各种查询。
二,功能概要
2.1.1对于管理员AdminOp:
1>管理员操作类AdminOp操作对象是车次集合cars与站点集合stops,其功能包括对车次集合Cars与站点集合Stops中的任意一辆车或者站点的增,删,查,改;不可忽视的是车次和站点之间的联系。
2.1.2对于用户操作类ClientOp
1>用户操作类ClientOp操作对象也是车次集合cars与站点集合stops,其功能只有查询,各种查询,不改变数据。
2,规划思路
2.2.1梳理类之间的数据关系
1>管理员操作类AdminOp和用户操作类ClientOp
管理员操作类AdminOp和用户操作类ClientOp是两个操作类,它们的操作对象,也就是数据成员是相同的,车次集合Cars, 站点集合Stops,即可以让管理员AdminOp和用户ClientOp继承车次集合Cars和站点集合Stops
2>车次集合Cars和站点集合Stops
车次集合Cars和站点集合Stops是两个相对独立又相联系的集合类,可以将其组合在一起,形成一个车次站点集合类CarsAStops,
3>车次站点集合类CarsAStops
车次站点集合类CarsAStops包含车次类OneCar和站点类Stop,即两个向量中的元素分别为车次类OneCar和站点类Stop;对于车次类Onecar而言,包括车次的基本信息和列车信息集合类CarInfos;对于站点类Stop而言,包括站点的基本信息和列车信息集合类CarInfos;由此可以看出,车次类OneCar和站点类Stop有共同的的数据成员:列车信息集合类CarInfos,则可以将其拿出单独成类,让车次类OneCar和站点类Stop都继承它。
4>列车信息集合类CarInfos
列车信息集合类CarInfos为元素列车信息类CarInfo的向量,该元素即包括某车次在在某站的基本信息以及停靠和发车时间,包含一个时间类Time;
5>时间类Time
只包含时hour和分minute两个基本数据成员
2.2.2梳理类之间的功能关系
1>管理员操作类AdminOp和用户操作类ClientOp
管理员操作类AdminOp和用户操作类ClientOp要实现的功能有相同的也有不同的,相同的功能包含在列车信息集合类CarsAStops里,两者直接继承即可,不同功能在自身类内实现。
两者相同的功能有:
其一:按车名,车次查找,得到所有的车次或者站点信息,都在列车信息集合类CarsAStops里直接实现;
其二:从数据文件里面读取站点和车次数据、将数据信息保存到文件里,因为管理员操作类AdminOp和用户操作类ClientOp的操作对象不仅仅是类型一样,内容也是统一的,即他们操作的数据文件也是相同的,则可将从文件读入数据,将数据输出到文件也写入列车信息集合类CarsAStops,对CarsAStops操作,也就是对车次集合Cars和站点集合Stops的直接操作。
两者不同的功能:
其一:对于管理员操作类AdminOp而言,更重要的是信息的维护工作。首先,是一条线路的从无到有,要对Cars和Stops进行基本信息的输入,之后再对之前加入的车次Car逐一进行增加停靠站点和停靠时间,与此同时对其中涉及的站点Stop也添加相应的记录;其次,对指定车次Car进行增加,删除,修改停靠站点操作,则对应的站点Stop作相应的改变,则需要对站点Stop进行增加、删除或者查找、修改时间的操作。
其二:对用户操作类ClientOp而言,除了基本的查询,更多的是需要相对精准的查询。包括按起始站和终点站的查询、按起始站和终点站以及有发车时间限制的查询、按起始站和终点站以及有终点到达时间限制的查询,则需要对大量的车站Stops和车次Cars进行更加精准快速的查询。
2>车次集合Cars和站点集合Stops
两个集合功能十分相似,且前面解释了将车次集合Cars和站点集合Stops合并为一个类进行操作,其功能则在合并后的车次站点集合类CarsAStops实现。
3>车次站点集合类CarsAStops
车次站点集合类CarsAStops包含以车次类OneCar和站点类Stop为元素的两向量,两向量实现功能与,两者具有相同的功能,则只详细阐述车次类Car的功能及与其他类的关系。
当对管理员提供修改某车次某站点的信息时、对用户提供更加精准的查询时,都需要对列车信息集合类CarInfos中的信息进行筛选比较;用户查询到后还要将该车基本信息以及两站起止时间直观的输出到屏幕上。
4>列车信息集合类CarInfos
当指定某车或者某站点时,其余的就是对该车或者该站点进行列车信息CarInfos进行查找,修改,和输出操作,可修改的数据成员包括到站时间和发车时间两个时间类Time对象。
5>时间类Time
只包含时hour和分minute两个基本数据成员
三,实现代码
#include<bits/stdc++.h>
using namespace std;
class Time{
int hour,
minute;
public:
Time(int a=-1,int b=-1):hour(a),minute(b){}
Time(const Time &obj){
hour=obj.hour;
minute=obj.minute;
}
int getHour(){return hour;}
int getMinute(){return minute;}
Time getTime(){return *this;}
void set(int a,int b){
hour=a;
minute=b;
}
bool operator<(const Time&t1)const{
return hour!=t1.hour ? hour<t1.hour : minute<t1.minute;
}
bool operator==(const Time &t1)const{
if(hour==t1.hour&&minute==t1.minute)
return true;
else return false;
}
friend istream&operator>>(istream &is,Time&t){
is>>t.hour;
is>>t.minute;
return is;
}
friend ostream&operator<<(ostream &os,const Time&t){
os<<t.hour<<" ";
os<<t.minute<<" ";
return os;
}
};
class CarInfo{
string carName;
string stopName;
Time cameTime;
Time goTime;
public:
CarInfo(){
carName="AAA"; //cameTime.set(-1,-1);goTime.set(-1,-1);无参数时Time类默认构造成-1
stopName="中国";
}
CarInfo(string cName,string sName,Time t1,Time t2){
carName=cName;
stopName=sName;
cameTime=t1;
goTime=t2;
}
CarInfo(string cName,string sName,int a,int b,int c,int d):carName(cName),stopName(sName),cameTime(a,b),goTime(c,d){}
string getCarName(){return carName;}
string getStopName(){return stopName;}
Time getCameTime(){return cameTime;}
Time getGoTime(){return goTime;}
CarInfo getCar_record(){return *this;}
void setCarName(string s){carName=s;}
void setStopName(string s){stopName=s;}
void setCameTime(Time t1){cameTime=t1;}
void setCameTime(int a,int b){cameTime.set(a,b);}
void setGoTime(Time t2){goTime=t2;}
void setGoTime(int a,int b){goTime.set(a,b);}
void set(string cName,string sName,Time t1,Time t2){
carName=cName;
stopName=sName;
cameTime=t1;
goTime=t2;
}
void set(string cName,string sName,int a,int b,int c,int d){
carName=cName;
stopName=sName;
cameTime.set(a,b);
goTime.set(c,d);
}
bool operator ==(const CarInfo &c_r1)const{
if(cameTime==c_r1.cameTime)
return true;
else return false;
}
friend istream &operator >>(istream &is,CarInfo &obj){
is>>obj.carName;
is>>obj.stopName;
is>>obj.cameTime;
is>>obj.goTime;
return is;
}
friend ostream &operator<<(ostream &os,const CarInfo &obj){
os<<obj.carName<<"\t";
os<<obj.stopName<<"\t";
os<<obj.cameTime<<"\t";
os<<obj.goTime<<endl;
return os;
}
};
class CarInfos{
protected:
int rNum;
vector<CarInfo> record;
vector<CarInfo>::iterator p_cr1,p_cr2;
//在stop中使用
multimap<string,int> m_carName;//按车次查询该元素所在位置
multimap<string,int>::iterator pm_cN1,pm_cN2;
//只在车次中使用
multimap<string,int> m_stopName;//按站点查询该元素所在位置
multimap<string,int>::iterator pm_sN1,pm_sN2;
multimap<Time,int> m_cameTime;//按到达时间查询该元素所在位置
multimap<Time,int>::iterator pm_cT1,pm_cT2;
public:
CarInfos(){rNum=0;}
int getRNum(){return rNum;}
Time getCameTime(string carN){
pm_cN1=m_carName.find(carN);
return record[pm_cN1->second].getCameTime();
}
Time getGoTime(string carN){
pm_cN1=m_carName.find(carN);
return record[pm_cN1->second].getGoTime();
}
void getRecords(){//美观的输出记录用的;
p_cr1=record.begin();
p_cr2=record.end();
int x=0;
for(p_cr1;p_cr1!=p_cr2;p_cr1++){
cout<<" 记录编号:"<<++x ;
cout<<" 列车名:"<<p_cr1->getCarName()<<" 车站名为:"<<p_cr1->getStopName()
<<" 到达时间:"<<p_cr1->