队列简单应用

一、问题描述:

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 }
原文地址:https://www.cnblogs.com/pandang/p/4849223.html