• 模拟服务台前的排队问题


    #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(" 上一个顾客到达的时间:%d,现在也入列 ",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(" 银行下班,不再接待新客户!");

                printf(" 上一个顾客到达的时间:%d,现在也入列 ",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(" 客户离开时间:%d,事件也删除 ",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(" 客户办理总时间为: %d 分钟,客户办理平均时间: %f 分钟 ",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(" 队列状态: ");

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

          {

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

            QueueTraverse(&q[i]);

        }

        printf(" ");

    }

     

    //显示事件表状态

    void PrintEventList()

    {

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

        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("内存分配失败! ");

            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("链表为空! ");

               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 ",p->OccurTime,p->NType);

               }

     

        printf(" ");

        return OK;

    }

     

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

     

    //初始化队列Q

    int InitQueue(LinkQueue *Q)

    {

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

        if(!Q->front)

          {

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

            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("队列为空,不能再进行出列操作! ");

           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("内存分配失败! ");

            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("队列为空. ");

            return ERROR;

        }

        while(p)

          { 

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

            p=p->next;

        }

        printf(" ");

        return OK;

    }

  • 相关阅读:
    Thinkphp的 is null 查询条件是什么,以及exp表达式如何使用
    thinkphp5多文件上传如何实现
    如何动态改变audio的播放的src
    js插件---10个免费开源的JS音乐播放器插件
    html5页面怎么播放音频和视频
    Thinkphp5图片上传正常,音频和视频上传失败的原因及解决
    leetcode
    HTML5 画一张图
    Linux内核和根文件系统引导加载程序
    [dp] hdu 4472 Count
  • 原文地址:https://www.cnblogs.com/youdiaodaxue16/p/7857771.html
Copyright © 2020-2023  润新知