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

本文主要是介绍严蔚敏 数据结构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;  
}  


这篇关于严蔚敏 数据结构C语言 银行排队队列 离散事件模拟的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/796738

相关文章

hdu1180(广搜+优先队列)

此题要求最少到达目标点T的最短时间,所以我选择了广度优先搜索,并且要用到优先队列。 另外此题注意点较多,比如说可以在某个点停留,我wa了好多两次,就是因为忽略了这一点,然后参考了大神的思想,然后经过反复修改才AC的 这是我的代码 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<

禁止平板,iPad长按弹出默认菜单事件

通过监控按下抬起时间差来禁止弹出事件,把以下代码写在要禁止的页面的页面加载事件里面即可     var date;document.addEventListener('touchstart', event => {date = new Date().getTime();});document.addEventListener('touchend', event => {if (new

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

usaco 1.2 Transformations(模拟)

我的做法就是一个一个情况枚举出来 注意计算公式: ( 变换后的矩阵记为C) 顺时针旋转90°:C[i] [j]=A[n-j-1] [i] (旋转180°和270° 可以多转几个九十度来推) 对称:C[i] [n-j-1]=A[i] [j] 代码有点长 。。。 /*ID: who jayLANG: C++TASK: transform*/#include<

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

透彻!驯服大型语言模型(LLMs)的五种方法,及具体方法选择思路

引言 随着时间的发展,大型语言模型不再停留在演示阶段而是逐步面向生产系统的应用,随着人们期望的不断增加,目标也发生了巨大的变化。在短短的几个月的时间里,人们对大模型的认识已经从对其zero-shot能力感到惊讶,转变为考虑改进模型质量、提高模型可用性。 「大语言模型(LLMs)其实就是利用高容量的模型架构(例如Transformer)对海量的、多种多样的数据分布进行建模得到,它包含了大量的先验

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

poj 3190 优先队列+贪心

题意: 有n头牛,分别给他们挤奶的时间。 然后每头牛挤奶的时候都要在一个stall里面,并且每个stall每次只能占用一头牛。 问最少需要多少个stall,并输出每头牛所在的stall。 e.g 样例: INPUT: 51 102 43 65 84 7 OUTPUT: 412324 HINT: Explanation of the s

poj 2431 poj 3253 优先队列的运用

poj 2431: 题意: 一条路起点为0, 终点为l。 卡车初始时在0点,并且有p升油,假设油箱无限大。 给n个加油站,每个加油站距离终点 l 距离为 x[i],可以加的油量为fuel[i]。 问最少加几次油可以到达终点,若不能到达,输出-1。 解析: 《挑战程序设计竞赛》: “在卡车开往终点的途中,只有在加油站才可以加油。但是,如果认为“在到达加油站i时,就获得了一