• 队列简单应用


    一、问题描述:

    1、题目内容:使用队列模拟理发馆的排队现象,通过仿真手法评估其营业状况。

    设某理发馆设有N把理发椅,可同时为N位顾客进行理发。当顾客进门时,若有空闲理发椅,则立即入座理发,否则依次排队候理,一旦有顾客理完发离去时,排在队头的顾客便开始理发。假若理发馆每天连续营业T小时(只要有顾客等待,理发椅就不空),求一天内顾客在理发馆内的平均逗留时间(包括理发所需时间和排队等候的时间)与顾客排队等候理发的人数的平均值(排队长度的平均值)。

    2、基本要求

    (1)当给定理发椅数及营业时间后,由随机数确定顾客理发时间及进门间隔时间,求出一天内顾客在理发馆平均逗留时间、平均队长及关门后收尾工作的时间。

    (2)由用户读入的数据仅为理发椅数及营业时间。营业的时间以分钟计,理发椅数及关门时间均为整型,且均大于等于1。

    3、测试数据

     理发椅数目N及关门时间由用户读入,第一个顾客进门的时刻为0,之后每个顾客的进门时刻在前一个顾客进门时设定。即在进门事件发生时随即产生两个随机数(DU,IN),DU为进门顾客理发所需的服务时间(简称理发时间);IN为下一个顾客到达的时间间隔(简称间隔时间)。

    二、实现提示:

     R为由随机数发生器的随机数,顾客理发时间和顾客之间的间隔时间不妨假设与R有关,可以由下式确定:

    DU=15+R%50    IN=2+R%10

      1 //2013-5-25
      2 //panda
      3 
      4 //定义客户类
      5 //Guest.h
      6 #pragma once
      7 
      8 #ifndef _GUEST
      9 #define _GUEST
     10 
     11 class Guest
     12 {
     13 public:
     14     int id;                //客户id
     15     int swtime;            //记录客户进店的时间
     16     int servertime;        //服务时间
     17     int ncgtime;        //下个客户到达时间
     18 public:
     19     Guest();            //默认构造函数
     20     Guest(int id,int swtime,int stime,int ncgtime);
     21     Guest(const Guest& g);    //复制构造函数
     22     Guest& operator=(const Guest& g);    //重载=运算符
     23 };
     24 
     25 #endif
     26 
     27 //panda
     28 //2013-5-21
     29 //Queue.h
     30 #pragma once
     31 #ifndef _QUEUE
     32 #define _QUEUE
     33 #include"Guest.h"
     34 
     35 #ifndef _LNODE
     36 #define _LNODE
     37 //节点结构
     38 struct LNode{
     39     Guest data;    //值域
     40     LNode* next;    //连接指针域
     41 };
     42 #endif
     43 
     44 class Queue{
     45 private:            //数据定义
     46     LNode* front;    //队首指针
     47     LNode* rear;    //队尾指针
     48 public:                //操作
     49     Queue();                    //初始化队列
     50     void InitQueue();            //初始化队列,置为空
     51     void EnQueue(LNode item);    //将新元素插入到队尾
     52     LNode OutQueue();            //从队列中删除队首元素并返回
     53     LNode PeekQueue();            //返回队列元素,但是不删除
     54     bool EmptyQueue();            //判断队列是否为空
     55     void ClearQueue();            //清除队列,使之为空
     56     int GetQueueLength();        //获得队列的长度
     57     //debug
     58     //void PrintQueue();            //输出队列
     59 };
     60 #endif
     61 
     62 //panda
     63 //2013-5-23
     64 //BarBerShop.h
     65 #pragma once
     66 #ifndef _BARBERSHOP
     67 #define _BARBERSHOP
     68 #include"Queue.h"
     69 //barbershop  定义理发店类
     70 
     71 class BarBerShop
     72 {
     73 private:
     74     // 店铺属性
     75     int chair;                //n把发椅
     76     Queue* chairqueue;        //n把发椅的相应的队列
     77     //int startime;            //开始营业时间
     78     int workhour;            //营业时间长度
     79     int workingtime;        //营业时间,是分为单位
     80     static int guestid;        //客户id分配
     81     //问题
     82     float atime;                //客人平均逗留时间,等待时间和理发时间   把每个客人的逗留时间加起来,等停止营业的时候在除于中的客人总数
     83     int samplingtimes;        //采样次数,即循环次数
     84     float aqlength;            //平均队列长度                          把每次循环的平均队长再除以中的循环次数
     85     int cworktime;            //关门后收尾工作时间                    
     86     //状态变量
     87     int ngct;                //下个客人到达时间,既调用produceguest函数的时间点
     88     int* stq;                //每条队列的队首客户的服务剩余时间
     89     int ctime;                //运行中的时间点
     90     int cuttime;            //下次运行的时间片
     91     //config setting 
     92     static const int stime=15;        //服务时间常量
     93     static const int sftime=50;        //服务时间因子
     94     static const int ngtime=2;        //下一个客人到达时间常量
     95     static const int ngftime=10;    //下一个各人到达时间因子
     96 public:
     97     BarBerShop();            //默认构造函数
     98     void RunWorking();        //接口,封装了整个营业流程
     99     void PrintData();        //输出统计数据
    100 protected:
    101     void PrepareWork();                                //开门前的准备工作,如打扫卫生,清理桌面
    102     void StartWork();                                //开始营业挣钱娶老婆
    103     void CloseDoor();                                //关门和老婆吃饭散步去
    104     int DistributeGuest(Guest& g,int time);            //分发客户,原则是那里人少添加到那个队列里,并返回是第几队队列(虽然理论上,那个队列的人所用的服务时间最少应该添加到那个队列里,但是在真正的生活中,一般都是排在人少的那条队列后面)
    105     Guest ProduceGuest();                            //返回客户id,和下个客户到达时间,和该客户到达时间
    106     void QueueWork(Queue queue);                    //每条队列的处理函数
    107 private://辅助函数
    108     //int MinNumber(int* array,int ngct,int alength);    //求最小值
    109     int MinQueue(Queue* q,int length);                    //求队列中人最少的一条
    110     int GetCutTime(int ngct,int* stq,int l);            //ngct下个客户到达时间,stq客户服务剩余时间,l为长度 获取本轮循环的减少时间,返回值表示下次循环是那个对象的执行时间到了 -1表示下个客户到了 
    111     bool EmptyQueueChair(Queue* q,int l);                //判断队列数组是否全为空
    112     float GetAverageQueueLength(Queue* q,int l);            //获取队列的平均长度
    113 };
    114 #endif
    115 
    116 //panda
    117 //2013-5-25
    118 //Guest.cpp 
    119 #include"Guest.h"
    120 //
    121 //默认构造函数
    122 //
    123 Guest::Guest()
    124 {}
    125 //
    126 //
    127 //
    128 Guest::Guest(int id,int swtime,int stime,int ncgtime)
    129 {
    130     this->id=id;
    131     this->swtime=swtime;
    132     this->servertime=stime;
    133     this->ncgtime=ncgtime;
    134 }
    135 //
    136 //复制构造函数
    137 //
    138 Guest::Guest(const Guest& g)
    139 {
    140     id=g.id;
    141     swtime=g.swtime;
    142     servertime=g.servertime;
    143     ncgtime=g.ncgtime;
    144 }
    145 //
    146 //重载=
    147 //
    148 Guest& Guest::operator=(const Guest& g)
    149 {
    150     id=g.id;
    151     swtime=g.swtime;
    152     servertime=g.servertime;
    153     ncgtime=g.ncgtime;
    154     return *this;
    155 }
    156 
    157 //2013-5-21
    158 //panda
    159 //Queue.cpp
    160 #include<iostream>
    161 #include"Queue.h"
    162 using namespace std;
    163 
    164 //Queue成员函数实现
    165 
    166 //
    167 //初始化队列,置为空
    168 //
    169 void Queue::InitQueue()
    170 {
    171     front=rear=NULL;
    172 }
    173 //
    174 //将新元素插入到队尾
    175 //
    176 void Queue::EnQueue(LNode item)
    177 {
    178     //创建待插入的节点,并申请内存空间 
    179     LNode* newnode=new LNode();
    180     //填充数据
    181     newnode->data=item.data;
    182     newnode->next=NULL;
    183     //插入到队尾
    184     if(rear==NULL)
    185     {
    186         //如果链表为空,则新的结点既是队首又是队尾
    187         front=rear=newnode;
    188     }else{
    189         //如链表非空,则新结点被连接到队尾并修改队尾指针
    190         rear=rear->next=newnode;
    191     }
    192 }
    193 //
    194 //从队列中删除队首元素并返回
    195 //
    196 LNode Queue::OutQueue()
    197 {
    198     //如果链队为空,则返回
    199     if(front==NULL)
    200     {
    201         cerr<<"链队为空,无法删除"<<endl;
    202         exit(1);
    203     }
    204     //储存待返回内容
    205     LNode node;
    206     node.data=front->data;
    207     node.next=NULL;
    208     //队首指针前移
    209     LNode* delnode=front;
    210     front=front->next;
    211     delete delnode;
    212     //若删除后链队为空,则使队尾指针为空
    213     if(front==NULL)
    214     {
    215         rear=NULL;
    216     }
    217     return node;
    218 }
    219 //
    220 //返回队列元素,但是不删除
    221 //
    222 LNode Queue::PeekQueue()
    223 {
    224     if(front==NULL)
    225     {
    226         cerr<<"链队为空,无队首元素。"<<endl;
    227         exit(1);
    228     }
    229     //返回队首元素
    230     LNode node;
    231     node.data=front->data;
    232     node.next=NULL;
    233     return node;
    234 }
    235 //
    236 //判断队列是否为空
    237 //
    238 bool Queue::EmptyQueue()
    239 {
    240     return front==NULL;
    241 }
    242 //
    243 //清除队列,使之为空
    244 //
    245 void Queue::ClearQueue()
    246 {
    247     //队首指针赋给p
    248     LNode* p=front;
    249     //依次删除队列中的每个结点
    250     while (p!=NULL)
    251     {
    252         front=front->next;
    253         delete p;
    254         p=front;
    255     }//循环结束后队首指针已经为空
    256     //置队尾指针为空
    257     rear=NULL;
    258 }
    259 //
    260 //debug 输出队列
    261 //
    262 //void Queue::PrintQueue()
    263 //{
    264 //    if (front==NULL)
    265 //    {
    266 //        cout<<"队链为空。"<<endl;
    267 //        return ;
    268 //    }
    269 //    LNode *p=front;
    270 //    while (p!=NULL)
    271 //    {
    272 //        cout<<p->data<<" ";
    273 //        p=p->next;
    274 //    }
    275 //}
    276 //
    277 //初始化队列
    278 //
    279 Queue::Queue()
    280 {
    281     front=rear=NULL;
    282 }
    283 //
    284 //获得队列的元素的长度
    285 //ok
    286 int Queue::GetQueueLength()
    287 {
    288     int length=0;//存储队列长度
    289     LNode *p=front;
    290     while (p!=NULL)
    291     {
    292         ++length;
    293         p=p->next;
    294     }
    295     return length;
    296 }
    297 
    298 //panda
    299 //2013-5-24
    300 
    301 //BarBerShop类的实现
    302 //BarBerShop.cpp
    303 #include"BarBerShop.h"
    304 #include"Guest.h"
    305 
    306 #include<iostream>
    307 using namespace std;
    308 
    309 //初始化静态成员变量
    310 int BarBerShop::guestid=0;
    311 //
    312 //准备工作,读入数据  呵呵~
    313 //ok
    314 void BarBerShop::PrepareWork()
    315 {
    316     cout<<"请输入理发店椅子的数目:";
    317     cin>>chair;
    318     /*if(chair<=0)
    319     {
    320     cout<<"输入数据有误,请重新输入!"<<endl;
    321     cin>>chair;
    322     }*/
    323     //为每张椅子生成一条队列
    324     chairqueue=new Queue[chair];
    325     stq=new int[chair];
    326     cout<<"请输入营业时间(以小时为单位):";
    327     cin>>workhour;
    328     /*if(workhour<8)
    329     {
    330     cout<<"请不要偷懒,8个小时都不够,什么时候才能挣够钱娶老婆啊?!亲~,请重新输入"<<endl;
    331     cin>>workhour;
    332     }else if (workhour>24)
    333     {
    334     cout<<"亲~,一天才25个小时,你要做多久啊?!会累死人的,请重新输入数据"<<endl;
    335     cin>>workhour;
    336     }*/
    337     workingtime=workhour*60;    //化为分钟
    338     cout<<"营业时间长度为"<<workingtime<<"分钟。"<<endl;
    339 }
    340 //
    341 //分发客户
    342 //ok
    343 int BarBerShop::DistributeGuest(Guest& guest,int time)
    344 {
    345     //找出队列中最少人的那一条
    346     int i=MinQueue(chairqueue,chair);
    347     LNode node;
    348     node.data=guest;
    349     node.next=NULL;
    350     //把结点放在相应的队列
    351     chairqueue[i].EnQueue(node);
    352     cout<<""<<time<<"时刻,id为"<<guest.id<<"的客户进到店,并排在第"<<i<<"条队列里。"<<endl;
    353     return i;
    354 }
    355 //
    356 //生产客户
    357 //ok
    358 Guest BarBerShop::ProduceGuest()
    359 {
    360     Guest nguest;
    361     //填充guest对象
    362     nguest.id=guestid++;        
    363     nguest.ncgtime=ngtime+rand()%ngftime;
    364     nguest.servertime=stime+rand()%sftime;
    365     return nguest;
    366 }
    367 //
    368 //开始营业
    369 //
    370 //通过while循环,递减workingtime变量来模拟时间运动,
    371 //并通过各个变量来记得下次该函数的调用时间
    372 //来模拟营业的流程
    373 void BarBerShop::StartWork()
    374 {
    375     //开始营业
    376     cout<<"在0点"<<"开始营业,欢迎光临!(方便数据的调试,以0点开始营业)"<<endl;
    377     //int ngct=0;                    //下个客户到达时间,即调用produceGuest函数的时间
    378     //int* stq=new int[chair];    //每条队列的客户服务剩余时间
    379     //清空为0
    380     for (int i = 0; i < chair; i++)
    381     {
    382         stq[i]=0;
    383     }
    384     //int cuttime=0;                //每次循环将要减少的时间
    385     //int ctime=0;                    //当前时间                
    386     //int workprogress=workingtime;            //工作进度
    387     while (ctime<workingtime)
    388     {
    389         //开始工作
    390         //相当于执行一轮
    391         cuttime=GetCutTime(ngct,stq,chair);
    392         //每循环一次,各个时间片都减去本次的循环时间片
    393         //workprogress-=cuttime;
    394         //判断cuttime是否超出范围
    395         if ((ctime+cuttime)>workingtime)
    396         {
    397             cuttime=workingtime-ctime;
    398         }
    399         ctime+=cuttime;    
    400         ngct-=cuttime;
    401         for (int i = 0; i < chair; i++)
    402         {
    403             if (stq[i]!=0)
    404             {
    405                 stq[i]-=cuttime;
    406             }
    407 
    408         }
    409         //具体执行的内容
    410         //客户部分
    411         if (ngct==0&&ctime!=workingtime)        //如果下个客户到达的时间到了,且没到关门时间,那就生产一个客户,并投递到相应的队列里
    412         {
    413             Guest g=ProduceGuest();
    414             //stq只记录队列首位客户的服务时间
    415             g.swtime=ctime;                        //记录进店时间
    416             int qindex=DistributeGuest(g,ctime);
    417             if (stq[qindex]==0)
    418             {
    419                 stq[qindex]=g.servertime;
    420             }
    421             //stq[DistributeGuest(g,ctime)]=g.servertime;    //分发客户,并记录服务时间
    422             ngct=g.ncgtime;    //记录下个客户到达时间
    423         }
    424         //理发队列
    425         for (int i = 0; i < chair; i++)
    426         {
    427             //队列里有客户在等,且执行时间到了
    428             if (stq[i]==0&&chairqueue[i].GetQueueLength()!=0)
    429             {
    430                 //弹出队首元素
    431                 LNode opnode=chairqueue[i].OutQueue();
    432                 //记录该客户的等待时间
    433                 atime+=(ctime-opnode.data.swtime);
    434                 //更新stq变量
    435                 if (!chairqueue[i].EmptyQueue())
    436                 {
    437                     stq[i]=chairqueue[i].PeekQueue().data.servertime;
    438                 }
    439 
    440                 cout<<""<<ctime<<"时刻,第"<<i<<"条队列的id为"<<opnode.data.id<<"的客户理完发。"<<endl;
    441             }
    442         }
    443         //获取队列的平均长度
    444         aqlength+=GetAverageQueueLength(chairqueue,chair);
    445         //统计函数调用次数
    446         ++samplingtimes;
    447     }
    448     cout<<"下班时间到了,不接客了,把剩下的客人剪完就吃饭去,好饿啊。"<<endl;
    449 }
    450 //
    451 //求最小值
    452 //
    453 //int BarBerShop::MinNumber(int* array,int ngct,int alength)
    454 //{
    455 //    int min=array[0];
    456 //    //找出数组最小的值
    457 //    for (int i = 1; i < alength; i++)
    458 //    {
    459 //        if (min<array[i])
    460 //        {
    461 //            min=array[i];
    462 //        }
    463 //    }
    464 //    return (min>ngct)?ngct:min;
    465 //}
    466 //
    467 //求最少人的队列
    468 //ok
    469 int BarBerShop::MinQueue(Queue* q,int l)
    470 {
    471     int index=0;                        //最少人队列下标
    472     int l0=q[0].GetQueueLength();
    473     int li;                                //队列长度
    474     for (int i = 1; i < l; i++)
    475     {
    476         li=q[i].GetQueueLength();
    477         if (l0>li)
    478         {
    479             l0=li;
    480             index=i;
    481         }
    482     }
    483     return index;
    484 }
    485 //
    486 //获取本轮减少时间片,返回下去那个对象的执行时间到了
    487 //ok
    488 int BarBerShop::GetCutTime(int ngct,int *stq,int l)
    489 {
    490     //只有那些队列的长度不为0的队列的stq值才有效
    491     int min=ngct;
    492     //找出数组最小的值
    493     for (int i = 0; i < l; i++)
    494     {
    495         if (chairqueue[i].GetQueueLength()!=0)
    496         {
    497             if (min>stq[i])
    498             {
    499                 min=stq[i];
    500             }
    501         }
    502 
    503     }
    504     return (min>ngct)?ngct:min;
    505 }
    506 //
    507 //开始运作
    508 //
    509 void BarBerShop::RunWorking()
    510 {
    511     //准备工作
    512     PrepareWork();
    513     //开门迎客
    514     StartWork();
    515     //关门吃饭
    516     CloseDoor();
    517 }
    518 //
    519 //构造函数
    520 //ok
    521 BarBerShop::BarBerShop()
    522 {
    523     chair=0;
    524     chairqueue=NULL;
    525     workhour=0;
    526     workingtime=0;
    527     atime=0;
    528     aqlength=0;
    529     cworktime=0;
    530     ngct=0;
    531     stq=NULL;
    532     ctime=0;
    533     cuttime=0;
    534     samplingtimes=0;
    535     //guestid=0;
    536 }
    537 //
    538 //停止营业,清尾工作
    539 //还是觉得把这个清尾工作写成一个函数,尽管和startwork函数有不少相同的地方
    540 void BarBerShop::CloseDoor()
    541 {
    542     int bltime=stime+sftime+100;                    //只是为了调用GetCutTime函数,无用参数变量
    543     while (!EmptyQueueChair(chairqueue,chair))        //只要队列不全为空就一直循环
    544     {
    545         cuttime=GetCutTime(bltime,stq,chair);        //获取循环减少的时间片
    546         ctime+=cuttime;                                //记录时间
    547         for (int i = 0; i < chair; i++)
    548         {
    549             if (stq[i]!=0)
    550             {
    551                 stq[i]-=cuttime;
    552             }
    553         }
    554         //理发队列
    555         for (int i = 0; i < chair; i++)
    556         {
    557             //队列里有客户在等,且执行时间到了
    558             if (stq[i]==0&&chairqueue[i].GetQueueLength()!=0)
    559             {
    560                 //弹出队首元素
    561                 LNode opnode=chairqueue[i].OutQueue();
    562                 //记录客户的等待时间
    563                 atime+=(ctime-opnode.data.swtime);
    564                 //更新stq变量
    565                 if (!chairqueue[i].EmptyQueue())
    566                 {
    567                     stq[i]=chairqueue[i].PeekQueue().data.servertime;
    568                 }
    569 
    570                 cout<<""<<ctime<<"时刻,第"<<i<<"条队列的id为"<<opnode.data.id<<"的客户理完发。"<<endl;
    571             }
    572         }
    573         //获取队列的平均长度
    574         aqlength+=GetAverageQueueLength(chairqueue,chair);
    575         //统计函数调用次数
    576         ++samplingtimes;
    577     }
    578     cout<<"终于弄好了,下班吃饭。今晚吃什么菜呢?!亲~"<<endl;
    579 }
    580 //
    581 //判断队列数组是否全为空
    582 //
    583 bool BarBerShop::EmptyQueueChair(Queue* q,int l)
    584 {
    585     for (int i = 0; i < l; i++)
    586     {
    587         if (false==q[i].EmptyQueue())
    588         {
    589             // 不为空
    590             return false;
    591         }
    592     }
    593     //为空
    594     return true;
    595 }
    596 //
    597 //获取队列的平均长度
    598 //
    599 float BarBerShop::GetAverageQueueLength(Queue* q,int l)
    600 {
    601     int averagelength=0;
    602     for (int i = 0; i < l; i++)
    603     {
    604         averagelength+=q[i].GetQueueLength();
    605     }
    606     return (averagelength/(float)l);
    607 }
    608 //
    609 //输出统计数据
    610 //
    611 void BarBerShop::PrintData()
    612 {
    613     cout<<"关门后的收尾工作时间为:"<<ctime-workingtime<<endl
    614         <<"顾客的平均逗留时间为:"<<(atime/(float)guestid)<<endl
    615         <<"排队队列的平均长度:"<<(aqlength/(float)samplingtimes)<<endl;
    616 }
    617 
    618 //panda
    619 //2013-5-21
    620 #include<iostream>
    621 #include"BarBerShop.h"
    622 
    623 using namespace std;
    624 
    625 int main()
    626 {
    627     BarBerShop bbshop;
    628     bbshop.RunWorking();
    629     bbshop.PrintData();
    630     return 0;
    631 }
  • 相关阅读:
    Apache Spark源码走读之4 -- DStream实时流数据处理
    Apache Spark源码走读之3 -- Task运行期之函数调用关系分析
    Apache Spark源码走读之2 -- Job的提交与运行
    Apache Spark源码走读之1 -- Spark论文阅读笔记
    Spark
    (转)互联网广告综述之点击率特征工程
    Java排序算法之冒泡排序
    java枚举
    第二课、数据的艺术---------------------狄泰软件学院
    第一课、进阶高手的大门--------------------狄泰软件学院
  • 原文地址:https://www.cnblogs.com/pandang/p/4849223.html
Copyright © 2020-2023  润新知