例题 例二 排队问题的系统模拟
  编制一个事件驱动仿真程序以模拟理发馆内一天的活动,要求输出在一天的营业时间内,到达的顾客人数、顾客在馆内的平均逗留时间和排队等候理发的平均人数以及在营业时间内空椅子的平均数。

  为计算出每个顾客自进门到出门之间在理发馆内逗留的时间,只需要在顾客"进门"和"出门"这两个时刻进行模拟处理即可。习惯上称这两个时刻发生的事情为"事件",整个仿真程序可以按事件发生的先后次序逐个处理事件,这种模拟的工作方式称为"事件驱动模拟",程序将依事件发生时刻的顺序依次进行处理,整个仿真程序则以事件表为空而告终。事件驱动仿真的算法大致如下:

算法3.5
  void BarberShop_Simulation( int chairNum, int closeTime )
 {
 // 理发馆业务模拟,统计一天内顾客在馆内逗留的平均时间
 // 和顾客在等待理发时排队的平均长度以及空椅子的平均数
 // chatrNum 为假设的理发馆的规模,closeTime 为营业时间

  OpenForDay;               // 初始化
  while MoreEvent do
  {
   EventDrived(OccurTime, EventType);   // 事件驱动
   switch (EventType) {
    case 'A' : CustomerArrived; break;  // 处理顾客到达事件
    case 'D' : CustomerDeparture; break; // 处理顾客离开事件
    default : Invalid;
   } // switch
  } // while
  CloseForDay;       // 计算平均逗留时间和排队的平均长度等
 } // BarberShop_Simulation
 
 
 
  假设理发馆内设有N把理发椅,可同时为N位顾客进行理发。对于在营业时间(假设为T小时)内进门的顾客,可能有两种情况。若当时理发馆内尚有空闲理发椅,则该顾客可立即入座理发,他在馆内的逗留时间即为他理发所需时间;否则需要排队候理,则他在馆内的逗留时间应为他理发所需时间和排队等候的时间之和。一旦有顾客理完发离去时,排在对头的顾客便开始理发。顾客的到达时间和理发所需时间均可随机生成,并约定,过了营业时间顾客不再进门,但仍需继续为已进入店内的顾客理发,直至最后一名顾客离开为止。
 动画

  为此需设置两个数据类型:一是事件表,登录顾客进门或出门的事件。表结构的每一项应包括事件类型(假设进门事件类型为 'A',出门事件类型为'D')和事件发生的时刻。为便于按事件发生的先后次序顺序进行处理,事件表应按发生的"时刻"有序。二是队列,记录排队等候理发的顾客情况,队列中的每个元素包括顾客进门的时刻和理发所需时间。
 
    数据类型定义:
  // "事件"的结构定义
 typedef struct {
  int occurTime; // 事件发生时刻
  char nType;  // 事件类型
 } ElemType,Event;

  // "事件表"的定义
 tydedef OrderedLinkList eventList;

  // "顾客"的结构定义
 typedef struct {
  int arrivalTime; // 顾客到达时间
  int duration;  // 顾客理发所需时间
 } qElemType, customer;

  // 候理顾客队列的定义
 typedef Queue waitingQueue;
 
  不失一般性,假设第一个顾客进门的时刻为0,显然,它应该是事件表的第一项,也就是程序要处理的第一个事件。之后每个顾客进门的时刻在前一个顾客进门时设定,即以两个顾客之间的时间间隔来确定下一个顾客的到达时间。顾客出门的时刻显然可以在开始理发的时候计算得到。