模拟服务台前的排队问题

#include <stdio.h>

#include <time.h>

#include <stdlib.h>

#include<malloc.h>

 

#define OK 1

#define ERROR 0

#define TRUE 1

#define FALSE 0

/**********************结构体************************************************/

 

 //事件表节点

typedef struct Event

      int OccurTime;  //事件发生时刻

    int NType;      //事件类型,0表示到达事件,1n表示四个窗口的离开事件

    struct Event *next;

}Event, *EventList;

 

 

//队列节点

typedef struct QElemType

{

    int ArriveTime;//到达时间

    int Duration;//办理业务所需时间

    struct QElemType *next;

}QElemType;

//队列指针

typedef struct

{

    QElemType *front;//头指针

    QElemType *rear;//尾指针

}LinkQueue;

/********************函数申明*************************************************/

//事件表基本操作函数

Event NewEvent(int occurT,int nType); //根据OccurTimeNType值,创建新事件

int InitList();//初始化事件链表

int OrderInsert(EventList  L, Event e);//将事件e按发生时间顺序插入有序链表L

int ListEmpty(EventList  L);//判断链表L是否为空,为空返回TRUE,否则返回FALSE

int DelFirst(EventList  L,Event *memorry); //链表L不为空,删除其首结点,用memorry返回,并返回OK;否则返回ERROR

int ListTraverse(EventList  L);//遍历链表

 

//队列基本操作函数

int InitQueue(LinkQueue *Q); //初始化队列Q

int EmptyQueue(LinkQueue *Q); //若队列Q为空,返回TRUE,否则返回FALSE

int DelQueue(LinkQueue *Q, QElemType *memrroy); //若队列Q不为空,首结点出队,用memrroy返回,并返回OK;否则返回ERROR

int EnQueue(LinkQueue *Q, QElemType e);//结点e入队Q

int QueueLength(LinkQueue *Q);//返回队列Q的长度,即元素个数

int GetHead(LinkQueue *Q, QElemType *memorry);//若队列Q不为空,用memrroy返回其首结点,并返回OK,否则返回ERROR

int QueueTraverse(LinkQueue *Q);//遍历队列Q

 

//排队主操作函数

int ShortestQueue();//获取最短队列的编号

void OpenForDay(); //初始化操作

void CustomerArrived();//顾客达到事件

void CustomerDepature();//顾客离开事件

void Bank_Simulation(); //银行排队模拟

 

//显示函数

void PrintEventList();//显示当前事件表

void PrintQueue();//显示当前窗口队列

/****************************全局变量*****************************************/

#define MAXSIZE 20  //宏定义

EventList ev;//事件指针变量

Event en;    //事件

LinkQueue q[MAXSIZE];//队列指针结构体数组

QElemType customer;//队列节点

int windows_num;//窗口个数

int TotalTime,CustomerNum;//顾客总时间,顾客总人数

int CloseTime=50;//关闭时间,即营业时间长度

 

/***********************主函数***********************************************/

int main()

      srand((unsigned)time(NULL));//设置随机种子

    Bank_Simulation();//银行模拟排队

    return 0;

}

/*******************银行排队主操作函数****************************************/

//银行开门初始化

void OpenForDay()

{

      int i;

      //全局变量赋初值

    TotalTime = 0; 

      CustomerNum = 0;

    //建立空事件表

    InitList();

    //对一天中的第一个事件发生事件和类型赋初值

    en.OccurTime=0;

    en.NType=0;

//第一个事件发生预订,插入事件表

    OrderInsert(ev,en);

      //得到用户输入窗口数

      printf("请输入排队窗口个数:");

      scanf("%d",&windows_num );

      while(windows_num<1 || windows_num>MAXSIZE)

           { printf("请输入120之间的数:");

             scanf("%d",&windows_num );

           }

    //得到用户输入银行关闭时间

    printf("请输入银行关闭时间:");

      scanf("%d",&CloseTime);

    //建立若干个空队列

    for(i = 0; i < windows_num; i++)

        InitQueue(&q[i]);//初始化windows_no个窗口队列

}

//客户到达事件处理

void CustomerArrived()

{

    int durtime,intertime,i,t;

    QElemType e;

 

    ++CustomerNum;

    intertime = rand()%5 + 1;  //间隔时间在5分钟内

    durtime = rand()%30 + 1;  //办理业务时间在30分钟内

    t = en.OccurTime + intertime;//下一客户到达的时间

   //银行尚未关门

    if(t < CloseTime)

           {   //下一个顾客来的预订,插入事件表

                 printf("\n上一个顾客到达的时间:%d,现在也入列\n",en.OccurTime);

                 OrderInsert(ev, NewEvent(t,0));

 

                 //顾客来到后入人数最少的队列

                 e.ArriveTime = en.OccurTime;//入队时间

                 e.Duration = durtime;//办理业务时间

                 i = ShortestQueue();//得到最短队列编号

                 EnQueue(&q[i], e);//入队操作

 

                 //如果入列后排在队头,则发生离开事件的预订

                 if(QueueLength(&q[i]) == 1)

                      OrderInsert(ev, NewEvent(en.OccurTime + durtime,  i+1));//窗口编号为队列序号加1

           }

 

    //银行关门(不再执行下一个来到事件的预订)

  else

           {

            printf("\n银行下班,不再接待新客户!");

            printf("\n上一个顾客到达的时间:%d,现在也入列\n",en.OccurTime);

 

          //顾客来到后入人数最少的队列

                 e.ArriveTime = en.OccurTime;//入队时间

                 e.Duration = durtime;//办理业务时间

                 i = ShortestQueue();//得到最短队列编号

                 EnQueue(&q[i], e);//入队操作

 

                 //如果入列后排在队头,则发生离开事件的预订

                 if(QueueLength(&q[i]) == 1)

                      OrderInsert(ev, NewEvent(en.OccurTime + durtime,  i+1));//窗口编号为队列序号加1

           }

      return ;

}

 

//顾客离开事件

void CustomerDepature()

{

    int i = en.NType - 1;//队列编号为窗口编号减1

 

      //删除队列首节点

    DelQueue(&q[i], &customer);

    printf("\n客户离开时间:%d,事件也删除\n",en.OccurTime);//输出顾客离开时间

    TotalTime += en.OccurTime - customer.ArriveTime;

 

      //如果队列不为空,则根据新的队列首节点,来确定离开事件预订

    if(!EmptyQueue(&q[i]))

      {

        GetHead(&q[i], &customer);

        OrderInsert(ev, NewEvent(en.OccurTime + customer.Duration,  i+1));//窗口编号为队列序号加1

    }

      return;

}

 

//银行排队模拟

void Bank_Simulation()

{

    OpenForDay();

    while(!ListEmpty(ev))//直到事件表为空

      {

           //删除事件表首结点,并得到首节点的数据作为判断依据

        DelFirst(ev, &en);

 

      //类型为0则表示到达事件,类型为1234...为离开事件

        if(en.NType == 0)

            CustomerArrived();

        else             

            CustomerDepature();

 

        PrintEventList();

        PrintQueue();

           system("PAUSE");//用户暂停操作,用于调试

    }

    printf("\n客户办理总时间为: %d 分钟,客户办理平均时间: %f 分钟\n",TotalTime,(float)TotalTime/CustomerNum);

}

 

 

//获取最短队列的编号

int ShortestQueue()

{

    int i,min;

      int a[MAXSIZE];

 

      min = 0;

 

    for(i = 0; i < windows_num; i++)

      {

      a[i] = QueueLength(&q[i]);

    }

 

    for(i = 1; i < windows_num; i++)

      {

        if(a[i] < a[min])

           {

            min = i;

        }

    }

    return min;

}

 

/*******************************显示函数*************************************/

//显示当前队列状态

void PrintQueue()

{

    int i;

    printf("\n队列状态:\n");

    for(i = 0; i < windows_num; i++)

      {

        printf("队列 %d :",  i+1);

        QueueTraverse(&q[i]);

    }

    printf("\n");

}

 

//显示事件表状态

void PrintEventList()

{

    printf("\n事件表状态:\n");

    ListTraverse(ev);

}

/************事件表基本操作函数***********************************************/

//根据OccurTimeNType值,创建新事件

Event NewEvent(int occurT,int nType)

{

    Event e;

    e.OccurTime = occurT;

    e.NType = nType;

    return e;

}

 

//空事件表的建立

int InitList()

{

    EventList L;

    L = (EventList)malloc(sizeof(Event));

    if(L == NULL)

      {

        printf("内存分配失败!\n");

        exit(-1);

    }

      else

      {

     L->next=NULL;

       ev = L;//得到空表的地址

      }

 

    return OK;

}

//向事件表中按时间升序插入元素

int OrderInsert(EventList L, Event e)

{

    EventList p,q;

   

      q = L;

      p = L->next;

 

      while(p && e.OccurTime > p->OccurTime)

      {

       q = p;

       p = p->next;

      }

 

    //q指向节点的后面挂新节点

      q->next = (EventList)malloc(sizeof(Event));

    //对新节点赋值

      q->next->OccurTime = e.OccurTime;

    q->next->NType = e.NType;

      q->next->next = p;

return  OK;

  

}

//判断链表L是否为空,为空返回TRUE,否则返回FALSE

 

int ListEmpty(EventList L)

{

   

    if((L->next == NULL))

        return TRUE;

    else

        return FALSE;

}

//链表L不为空,删除其首结点,用e返回,并返回OK;否则返回ERROR  

int DelFirst(EventList L,  Event *memorry)

{

    EventList  p ;

 

      if(ListEmpty(L) == TRUE   )

           {

           printf("链表为空!\n");

           return ERROR;

           }

      else

           {

           p = L->next;

           L->next = p->next;

        //保存数值

        *memorry = *p;

 

           free(p);

           return  OK;

           }

}

 

//遍历链表

int ListTraverse(EventList L) 

{

   

    EventList p ;

 

      p = L;

 

     while(p->next)

           {

           p = p->next;

        printf("时间:%d,类型:%d\n",p->OccurTime,p->NType);

           }

 

    printf("\n");

    return OK;

}

 

/**********************队列相关函数******************************************/

 

//初始化队列Q

int InitQueue(LinkQueue *Q)

{

    Q->front = Q->rear=(QElemType *)malloc(sizeof(QElemType));

    if(!Q->front)

      {

        printf("内存分配失败!\n");

        exit(-1);

    }

    Q->front->next=NULL;

    return OK;

}

 

//若队列Q为空,返回TRUE,否则返回FALSE

int EmptyQueue(LinkQueue *Q)

{

    if(Q->front == Q->rear)

        return TRUE;

    else

        return FALSE;

}

 

//若队列Q不为空,首结点出队,用memorry返回,并返回OK;否则返回ERROR

int DelQueue(LinkQueue *Q,  QElemType *memorry)

{

QElemType *p ;//节点指针

 

if(  EmptyQueue(Q))

      {

       printf("队列为空,不能再进行出列操作!\n");

       return ERROR;

      }

else

      {

        p = Q->front->next;

       *memorry = *p;

        Q->front->next = p->next;

        if(Q->rear == p)

             {

              Q->rear = Q->front;

             }

       free(p);

     return OK;

      }

 

}

//结点e入队Q

int EnQueue(LinkQueue *Q, QElemType e)

{

 QElemType* p;//节点指针

 

 p = (QElemType *)malloc(sizeof(QElemType));

 if(NULL == p)

       {

        printf("内存分配失败!\n");

        exit(-1);

       }

 else

      {

     *p = e;

       p->next = NULL;

       Q->rear->next = p;

       Q->rear = p;

       return OK;

      }

}

 

//返回队列Q的长度,即元素个数

int QueueLength(LinkQueue *Q)

{

      QElemType  * p;//队列节点指针

      int count ;

 

      count = 0;

      p = Q->front->next;//得到队列第一个节点的地址

      while(p)

           {

           count++;

           p = p->next;

           }

           return count;

}

 

 

//若队列Q不为空,用memorry返回其首结点,并返回OK,否则返回ERROR

int GetHead(LinkQueue *Q, QElemType *memorry)

{

    if(EmptyQueue(Q))

        return ERROR;

 

    *memorry = *(Q->front->next);

 

        return OK;

}

//遍历队列Q

int QueueTraverse(LinkQueue *Q)

{

   

    QElemType *p=Q->front->next;

 

    if(!p)

      {

        printf("队列为空.\n");

        return ERROR;

    }

    while(p)

      { 

          printf("(%d,%d)",  p->ArriveTime,p->Duration);

        p=p->next;

    }

    printf("\n");

    return OK;

}

 

posted @ 2017-11-18 20:03  离愁i  阅读(1061)  评论(0编辑  收藏  举报