严蔚敏 数据结构C语言 银行排队队列 离散事件模拟

以下代码源自http://blog.csdn.net/nuaazdh/article/details/7059630,在CentoS下用 【g++ -o bank bank.c 】编译通过,稍微修改。

系统每次随机生成的是1)当前顾客顾客的柜台被服务时间2)当前顾客和下一个顾客到达的间隔时间,记住这2点就理解了整个代码,书里说得不太清楚。每个顾客在银行的等待时间取决于队列里前一个节点的离开时间,而不是自己的到达时间+服务时间。

代码设置了EventList这个事件链表 ,来保存随机生成的顾客到达时间和服务时间,模拟排队业务。

不过现实生活中,顾客达到时间可以模拟,但是被服务时间一般不好模拟!不知道这样的事件驱动模型在哪个实际场景中有用?

//离散事件模拟,模拟银行营业时的排队情况  
//不考虑顾客中途离开,顾客到达事件随机,业务办理时间  
//长度随机,选择最短的队排队,不再换队  
//作者:nuaazdh  
//时间:2011年12月10日 08:52:37  
#include <stdio.h>  
#include <time.h>  
#include <stdlib.h>  
  
#define OK 1  
#define ERROR 0  
#define TRUE 1  
#define FALSE 0  
  
typedef int Status;  
typedef struct Event{   //事件类型  
    int OccurTime;  //事件发生时刻  
    int NType;      //事件类型,0表示到达事件,1至4表示四个窗口的离开事件  
    struct Event *next;  
}Event,ElemType;  
  
typedef struct{ //单向链表结构  
    ElemType *head;//头指针  
    ElemType *tail;//尾指针  
    int len;    //长度  
}LinkList;  
  
typedef LinkList EventList; //事件链表  
  
typedef struct QElemType{ //队列元素  
    int ArriveTime;//到达时间  
    int Duration;//办理业务所需时间  
    struct QElemType *next;  
}QElemType;  
  
typedef struct{//队列结构  
    QElemType *head;//头指针  
    QElemType *tail;//尾指针  
}LinkQueue;  
  
Event NewEvent(int occurT,int nType);  
    //根据OccurTime和NType值,创建新事件  
Status InitList(LinkList *L);  
    //初始化事件链表  
Status OrderInsert(LinkList *L,Event e);  
    //将事件e按发生时间顺序插入有序链表L中  
Status ListEmpty(LinkList *L);  
    //判断链表L是否为空,为空返回TRUE,否则返回FALSE  
Status DelFirst(LinkList *L,ElemType *e);  
    //链表L不为空,删除其首结点,用e返回,并返回OK;否则返回ERROR  
Status ListTraverse(LinkList *L);  
    //遍历链表  
Status InitQueue(LinkQueue *Q);  
    //初始化队列Q  
Status EmptyQueue(LinkQueue *Q);  
    //若队列Q为空,返回TRUE,否则返回FALSE  
Status DelQueue(LinkQueue *Q,QElemType *e);  
    //若队列Q不为空,首结点出队,用e返回,并返回OK;否则返回ERROR  
Status EnQueue(LinkQueue *Q,QElemType e);  
    //结点e入队Q  
int QueueLength(LinkQueue Q);  
    //返回队列Q的长度,即元素个数  
Status GetHead(LinkQueue *Q,QElemType *e);  
    //若队列Q不为空,用e返回其首结点,并返回OK,否则返回ERROR  
Status QueueTraverse(LinkQueue *Q);  
    //遍历队列Q  
  
//------------------//  
int Min(int a[],int n);  
    //返回长度为n的数组a第一个最小值的下标,从1开始  
int ShortestQueue();  
    //获取最短队列的编号  
void OpenForDay();  
    //初始化操作  
void CustomerArrived();  
    //顾客达到事件  
void CustomerDepature();  
    //顾客离开事件  
void Bank_Simulation();  
    //银行排队模拟  
void PrintEventList();  
    //输出事件队列  
void PrintQueue();  
    //打印当前队列  
//----全局变量-----//  
EventList ev;  
Event en;  
LinkQueue q[5];  
QElemType customer;  
int TotalTime,CustomerNum;  
int CloseTime=200;//关闭时间,即营业时间长度  
  
//--------------main()------------------//  
int main()  
{  
    Bank_Simulation();  
    return 0;  
}  
  
  
//--------------模拟排队----------------//  
void OpenForDay(){  
    //初始化操作  
    int i;  
    TotalTime=0;    CustomerNum=0;  
    InitList(&ev);//初始化事件队列  
    en.OccurTime=0;  
    en.NType=0;  
    OrderInsert(&ev,en);  
    for(i=1;i<=4;i++)  
        InitQueue(&q[i]);//初始化四个窗口队列  
}//OpenForDay  
  
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( en.OccurTime<CloseTime){//银行尚未关门  
        printf("A new customer arrived at:%d,his durTime=%d,the next intertime=%d|\n",en.OccurTime,durtime,intertime);//下一位顾客达到时间  
        OrderInsert(&ev,NewEvent(t,0));  
        i=ShortestQueue();//最短队列  
        e.ArriveTime=en.OccurTime;  
        e.Duration=durtime;  
        EnQueue(&q[i],e);  
        if(QueueLength(q[i])==1)  
            OrderInsert(&ev,NewEvent(en.OccurTime+durtime,i));  
    }else{
        printf("maxinum exceed!stop,en.OccurTime=%d,intertime=%d\n",en.OccurTime,intertime);
    }  
}  
  
void CustomerDepature(){  
    //顾客离开事件  
    int i=en.NType;  
    DelQueue(&q[i],&customer);  
    printf("A customer leaves at:%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));  
    }  
}  
  
void Bank_Simulation(){  
    //银行排队模拟  
    OpenForDay();  
    srand((unsigned)time(NULL));  
    while(!ListEmpty(&ev)){  
        DelFirst(&ev,&en); 
        printf("--------action--------------------------\n"); 
        if(en.NType==0)  
            CustomerArrived();  
        else  
            CustomerDepature();  
        PrintQueue();  
        PrintEventList();
    }  
    printf("\nTotal time is: %d min,average time is: %g min.\n",TotalTime,(float)TotalTime/CustomerNum);  
}  
  
void PrintQueue(){  
    //打印当前队列  
    int i;  
    for(i=1;i<=4;i++){  
        printf("Queue %d have %d customer(s):",i,QueueLength(q[i]));  
        QueueTraverse(&q[i]);  
    }  
    printf("\n");  
}  
  
void PrintEventList(){  
    //输出事件队列  
    printf("Current Eventlist is:\n");  
    ListTraverse(&ev);  
}  
int Min(int a[],int n){  
    //返回长度为n的数组a第一个最小值的下标,从0开始  
    int i,tmp,ind=0;  
    tmp=a[0];  
    for(i=1;i<n;i++){  
        if(a[i]<tmp){  
            tmp=a[i];  
            ind=i;  
        }  
    }  
    return ind;  
}  
  
int ShortestQueue(){  
    //获取最短队列的编号  
    int i,a[4];  
    for(i=1;i<=4;i++){  
        a[i-1]=QueueLength(q[i]);  
        //printf("队%d的长度为%d\n",i,QueueLength(q[i]));  
    }  
    return Min(a,4)+1;//队列从1开始编号  
}  
  
//-----------队和链表操作--------------//  
Event NewEvent(int occurT,int nType){  
    //根据OccurTime和NType值,创建新事件  
    Event e;  
    e.OccurTime=occurT;  
    e.NType=nType;  
    return e;  
}  
  
Status InitList(LinkList *L){  
    //初始化事件链表  
    L->head=L->tail=(ElemType *)malloc(sizeof(ElemType));  
    if(!L->head){  
        printf("Apply for memory error.LinkList initialize failed.\n");  
        exit(0);  
    }  
    L->head->next=NULL;  
    return OK;  
}  
  
Status OrderInsert(LinkList *L,Event e){  
    //将事件e按发生时间顺序插入有序链表L中  
    ElemType *p,*q,*newptr;  
    newptr=(ElemType *)malloc(sizeof(ElemType));  
    if(!newptr){  
        printf("Apply for memory error,new node can't insert intot the Eventlist.\n");  
        exit(0);  
    }  
    *newptr=e;  
    if(TRUE==ListEmpty(L)){//链表为空  
       L->head->next=newptr;  
       L->tail=newptr;  
       L->tail->next=NULL;  
       return OK;  
    }  
    q=L->head;  
    p=L->head->next;  
    while(p){//遍历整个链表  
        if(p->OccurTime>=newptr->OccurTime)  
            break;  
        q=p;  
        p=p->next;  
    }  
    q->next=newptr;  
    newptr->next=p;  
    if(!p)//插入位置为链表尾部  
        L->tail=newptr;  
    return OK;  
}  
  
Status ListEmpty(LinkList *L){  
    //判断链表L是否为空,为空返回TRUE,否则返回FALSE  
    if((L->head==L->tail)&&(L->head!=NULL))  
        return TRUE;  
    else  
        return FALSE;  
}  
  
Status DelFirst(LinkList *L,ElemType *e){  
    //链表L不为空,删除其首结点,用e返回,并返回OK;否则返回ERROR  
    ElemType *p=L->head->next;  
    if(!p)  
        return ERROR;  
    L->head->next=p->next;  
    *e=*p;  
    free(p);  
    if(L->head->next==NULL)  
        L->tail=L->head;  
    return OK;  
}  
  
Status ListTraverse(LinkList *L){  
    //遍历链表  
    Event *p=L->head->next;  
    if(!p){  
        printf("List is empty.\n");  
        return ERROR;  
    }  
    while(p!=NULL){  
        printf("OccurTime:%d,Event Type:%d\n",p->OccurTime,p->NType);  
        p=p->next;  
    }  
    printf("\n");  
    return OK;  
}  
  
Status InitQueue(LinkQueue *Q){  
    //初始化队列Q  
    Q->head=Q->tail=(QElemType *)malloc(sizeof(QElemType));  
    if(!Q->head){  
        printf("Apply for memory error.LinkQueue initialize failed.\n");  
        exit(0);  
    }  
    Q->head->next=NULL;  
    return OK;  
}  
  
Status EmptyQueue(LinkQueue *Q){  
    //若队列Q为空,返回TRUE,否则返回FALSE  
    if(Q->head==Q->tail&&Q->head!=NULL)  
        return TRUE;  
    else  
        return FALSE;  
}  
  
Status DelQueue(LinkQueue *Q,QElemType *e){  
    //若队列Q不为空,首结点出队,用e返回,并返回OK;否则返回ERROR  
    QElemType *p=Q->head->next;  
    if(!p)  
        return ERROR;  
    *e=*p;  
    Q->head->next=p->next;//修正队首指针  
    free(p);  
    if(!Q->head->next)//队空  
        Q->tail=Q->head;  
    return OK;  
}  
  
Status EnQueue(LinkQueue *Q,QElemType e){  
    //结点e入队Q  
    QElemType *p=(QElemType *)malloc(sizeof(QElemType));  
    if(!p){  
        printf("Apply for memory error,new element can't enqueue.\n");  
        exit(0);  
    }  
    *p=e;  
    p->next=NULL;  
    Q->tail->next=p;//插入队尾  
    Q->tail=p;//修改队尾指针  
    return OK;  
}  
  
int QueueLength(LinkQueue Q){  
    //返回队列Q的长度,即元素个数  
    int count=0;  
    QElemType *p=Q.head->next;  
    while(p){  
        p=p->next;  
        count++;  
    }  
    return count;  
}  
  
Status GetHead(LinkQueue *Q,QElemType *e){  
    //若队列Q不为空,用e返回其首结点,并返回OK,否则返回ERROR  
    if(EmptyQueue(Q))  
        return ERROR;  
    *e=*(Q->head->next);  
        return OK;  
}  
  
Status QueueTraverse(LinkQueue *Q){  
    //遍历队列Q  
    QElemType *p=Q->head->next;  
    if(!p){  
        printf("--Is empty.\n");  
        return ERROR;  
    }  
    while(p){  
        printf("(%d,%d) ",p->ArriveTime,p->Duration);  
        p=p->next;  
    }  
    printf("\n");  
    return OK;  
}  


  • 22
    点赞
  • 106
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值