队列的应用——飞机场模拟
问题描述:飞机场模拟如何安排哪架飞机进入跑道,方便跑道规划。简化为飞机场只有一条跑道,飞机分类为两大类,一类为天空中等待着陆的飞机,一类为陆地上等待起飞的飞机。因为天空中正在飞行的飞机在空中飞行会费油,故当有等待着陆的飞机和等待 起飞的飞机同时等待用跑道时,优先允许等待着陆的飞机运用跑道。
解决思路:因为飞机进跑道的顺序是先等待的飞机先进跑道,符合队列的性质。运用两个队列,一个队列存放等待着陆的飞机,一个队列存放等待起飞的飞机。出队表示进入跑道,如果等待着陆的飞机队列有元素优先出队,直到等待着陆的飞机队列为空时,等待起飞的队列元素再出队。
代码实现:(修改并添加课本上和老师上课讲的代码)
#include <iostream>
#include "queue.h"//头文件见队列笔记
using namespace std;
enum Plane_status {null, arriving, departing}; //枚举飞机状态:空闲,等待着陆,等待起飞
class Plane {
public:
Plane();
Plane(int flt, int time, Plane_status status);
void refuse() const;
void land(int time) const;
void fly(int time) const;
int started() const;
private:
int flt_num;//航班号
int clock_start;//进入跑道时间片
Plane_status state;//飞机状态
};
Plane::Plane()//无参的构造函数
{
flt_num=-1;//设为一个非法的值表示没有
clock_start=-1;
state=null;//设为空
}
Plane::Plane(int flt, int time, Plane_status status)//带参的构造函数
{
flt_num=flt;
clock_start=time;
state=status;
cout<<"航班号"<<flt ;//显示正在等待的飞机
if(status==arriving) //显示飞机状态
cout<<"等待着陆."<< endl;
else cout<<"等待起飞."<< endl;
}
void Plane::refuse()const
{
cout<<"航班号"<<flt_num;
if(state==arriving)
cout<<"去另一个机场"<<endl;//如果状态为等待着陆,显示去另一个机场
else cout<<"通知后起飞"<<endl;//如果状态为等待起飞,显示通知后起飞
}
void Plane::land(int time)const//陆地上
{
int wait=time-clock_start;//等待时间为等待起飞时间减进入跑道时间
cout<<time<<":航班号 "<<flt_num<<"着陆后"
<<wait<<"时间单位"<<((wait==1)?"":"s")<<"在着陆队列中。"<<endl;
}
void Plane::fly(int time) const //飞行中
{
int wait=time-clock_start;
cout<<time<<":航班号"<<flt_num<<"起飞后 "
<<wait<<"时间单位"<<((wait==1)?"":"s")<<" 在起飞队列中。"<<endl;
}
int Plane::started() const //运用跑道时间
{ return clock_start; }
typedef Plane Queue_entry;
enum Runway_activity{idle,land,depart}; //枚举跑道的应用状态空闲,着陆,起飞
class Runway {
public:
Runway(int limit);
Error_code can_land(const Plane& current);
Error_code can_depart(const Plane ¤t);
Runway_activity activity(int time, Plane &moving);
void shut_down(int time) const;
private:
Extended_queue landing; //队列每一项是一个飞机对象
Extended_queue takeoff;
int queue_limit;//队列数量限制
int num_land_requests;//请求着陆飞机数量
int num_takeoff_requests;//请求起飞飞机数量
int num_landings;//飞机着陆数量
int num_takeoffs;//飞机起飞数量
int num_land_accepted;//允许飞机着陆数量
int num_takeoff_accepted;//允许飞机起飞1数量
int num_land_refused;//拒绝飞机着陆数量
int num_takeoff_refused;//拒绝飞机起飞数量
int land_wait;//等待着陆总时间
int takeoff_wait;//等待起飞总时间
int idle_time;//跑道空闲总时间
};
Runway::Runway(int limit)
{
queue_limit=limit;
num_land_requests=num_takeoff_requests = 0;
num_landings=num_takeoffs = 0;
num_land_refused=num_takeoff_refused = 0;
num_land_accepted=num_takeoff_accepted = 0;
land_wait=takeoff_wait=idle_time = 0;
}
Error_code Runway::can_land(const Plane ¤t)//着陆飞机入队
{
Error_code result;
if(landing.size()<queue_limit)//着陆队列的长度小于队列限制
result=landing.append(current);//飞机入队
else result=fail;//入队失败
num_land_requests++;//请求着陆飞机数量增1
if(result!=success)
num_land_refused++;//入队失败拒绝着陆飞机增1
else num_land_accepted++;//入队成功允许着陆飞机增1
return result;
}
Error_code Runway::can_depart(const Plane ¤t)//起飞飞机入队
{
Error_code result;
if(takeoff.size()<queue_limit)
result=takeoff.append(current);
else result=fail;
num_takeoff_requests++;
if(result!=success)
num_takeoff_refused++;
else num_takeoff_accepted++;
return result;
}
Runway_activity Runway::activity(int time, Plane &moving)//跑道状态
{
Runway_activity in_progress;
if (!landing.empty())//这里体现了跑道优先考虑着陆飞机
{
landing.retrieve(moving);//获取队首元素
land_wait+=time-moving.started();
num_landings++;
in_progress=land;
landing.serve();//删除队首元素(一套不要忘记)
}else if(!takeoff.empty())
{
takeoff.retrieve(moving);
takeoff_wait+=time-moving.started();
num_takeoffs++;
in_progress=depart;
takeoff.serve();
}else
{
idle_time++;
in_progress=idle;
}
return in_progress;
}
void Runway::shut_down(int time) const
{
cout <<"模拟后结果"<<time<<"时间单位。"<<endl
<<"审核飞机总数"<<(num_land_requests+num_takeoff_requests)<<endl
<<"请求着陆飞机总数"<<num_land_requests<<endl
<<"请求起飞飞机总数"<<num_takeoff_requests<<endl
<<"允许着陆飞机总数"<<num_land_accepted<<endl
<<"允许起飞飞机总数"<<num_takeoff_accepted<<endl
<<"拒绝着陆飞机总数"<<num_land_refused<<endl
<<"拒绝起飞飞机总数"<<num_takeoff_refused<<endl
<<"着陆飞机总数"<<num_landings<<endl
<<"起飞飞机总数"<<num_takeoffs<<endl
<<"着陆队列长度"<<landing.size()<<endl
<<"起飞队列长度"<<takeoff.size()<<endl;
cout<<"跑道空闲时间百分比"<<100.0*((float)idle_time)/((float)time)<<"%"<<endl;
cout<<"着陆队列平均等待时间"<<((float)land_wait)/((float)num_landings)<<"时间单位"<<endl;
cout<<"起飞队列平均等待时间"<<((float)takeoff_wait)/((float)num_takeoffs)<<"时间单位"<<endl;
cout<<"平均观察到的飞机着陆率"<<((float)num_land_requests)/((float)time)<<"每时间单位"<<endl;
cout<<"平均观察到的飞机起飞率"<<((float)num_takeoff_requests)/((float)time)<<"每时间单位"<<endl;
}
void initialize(int &end_time, int &queue_limit, double &arrival_rate, double &departure_rate)//预置
{
cout<<"这个机场模拟项目只预设一条跑道"<<endl
<<"在每个时间单位飞机可以着陆或起飞"<<endl;
cout<<"有多少架飞机可以随时等待着陆或起飞?"<<flush;//flush表示什么都不加直接输出
cin>>queue_limit;
cout<<"模拟将运行多少时间单位?"<<flush;
cin>>end_time;
bool acceptable;
do{
cout<<"每单位时间的预计着陆数?"<<flush;
cin>>arrival_rate;
cout<<"每单位时间的预计起飞数?"<<flush;
cin>>departure_rate;
if(arrival_rate<0.0||departure_rate< 0.0)
cerr<<"这些比率必须是非负的。"<<endl;//cerr: 错误输出流,无缓冲,不可以重定向。输出的数据不经过缓冲区,直接放到指定的目标中,
//既然不经过缓冲区那么其它程序就无法把要输出的内容送到其他目标中,所以说它不能被重定向。
else acceptable = true;
if (acceptable&&arrival_rate+departure_rate>1.0)
cerr<<"安全警告:这个机场将会饱和。"<<endl;
} while(!acceptable);
}
void run_idle(int time)
{
cout<<time<<":跑道空闲"<<endl;
}
int main()
{
int end_time;
int queue_limit;
int flight_number = 0;
double arrival_rate, departure_rate;
initialize(end_time, queue_limit, arrival_rate, departure_rate);
Random variable;
Runway small_airport(queue_limit);
for(int current_time=0;current_time<end_time;current_time++)
{
int number_arrivals = variable.poisson(arrival_rate);
for(int i=0;i<number_arrivals;i++)
{
Plane current_plane(flight_number++, current_time, arriving);
if(small_airport.can_land(current_plane)!=success)
current_plane.refuse();
}
int number_departures= variable.poisson(departure_rate);
for(int j=0;j<number_departures;j++)
{
Plane current_plane(flight_number++, current_time, departing);
if (small_airport.can_depart(current_plane)!=success)
current_plane.refuse();
}
Plane moving_plane;
switch (small_airport.activity(current_time, moving_plane))
{
case land:moving_plane.land(current_time);break;
case depart:moving_plane.fly(current_time);break;
case idle:run_idle(current_time);
}
}
small_airport.shut_down(end_time);
}
思路扩展:
当一条跑道扩展成两条时,如何处理?
当跑道扩展成两条时,就可以将一条跑道设置为专门着陆的跑道,一条跑道设置为专门起飞的跑道。但可以考虑当着陆跑道被占用时,仍然有飞机等待着陆,此时若起飞跑道空闲,可使飞机降落在起飞跑道。