《数据结构》严蔚敏 离散时间模拟——银行排队 算法3_6 - 3_7
这个是借鉴了一下别人的代码的。原文:https://www.cnblogs.com/kangjianwei101/p/5225738.html(膜大佬)
这个问题综合性很高,把队列和链表的知识都照顾到了诶。
学习一下~
还是先放截图吧
3.6.h
#ifndef _3_6_H
#define _3_6_H
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<time.h> //provide seed
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define INDEFINE -3
#define SleepTime 1
#define DurationTime 20 // business time in a row
#define IntervalTime 10 // last customer come
typedef int Status;
//when a variable value is certain,could use enum
typedef enum
{
Arrive,Leave_1,Leave_2,Leave_3,Leave_4
}EventType;
typedef struct
{
int OccurTime;
EventType NType;
}Event;
typedef Event LElemType_L;
typedef struct LNode
{
LElemType_L data;
struct LNode * next;
}LNode;
typedef LNode* LinkList;
typedef LinkList EventList;
typedef struct
{
int ArrivedTime;
int Duration;
int Count;
}QElemType_L;
typedef struct QNode //队列也是要有下一个的
{
QElemType_L data;
struct QNode *next;
}QNode;
typedef QNode* QueuePtr;
typedef struct
{
QueuePtr front;
QueuePtr rear;
}LinkQueue;
//global variable
int gTotalTime,gCustomerNum;
int gCloseTime = 10;
EventList gEv;
Event gEn;
LinkQueue gQ[5];
QElemType_L gCustomerRcd;
//functions
void Bank_Simulation_1();
void OpenForDay();
Status MoreEvent();
void EventDrived(char * event);
void CustomerArrived();
void CustomerDeparture();
void Invalid();
void CloseForDay();
int cmp(Event a,Event b);
void Random(int *durtime,int *intertime);
Status OrderInsert(EventList gEv,Event gEn,int(cmp)(Event,Event));
int Minimum();
void Show();
void Bank_Simulation_2();
#endif
3.6.c
#include "3_6.h"
void
Show()
{
int i ;
QueuePtr p;
for(i = 1;i<=4;i++)
{
for(p = gQ[i].front; p ; p = p->next)
{
if(p == gQ[i].front)
{
if(i == 1)
printf("first: ⭕️");
if(i == 2)
printf("second:⭕️");
if(i == 3)
printf("third: ⭕️");
if(i == 4)
printf("forth: ⭕️");
}
else
printf(" (%03d) ",p->data.Count);
if(p == gQ[i].rear)
printf("\n");
}
}
sleep(SleepTime);
printf("\n");
}
void
Random(int *durtime,int *intertime)
{
srand((unsigned)time(NULL));
*durtime = rand()%DurationTime+1;
*intertime = rand()%IntervalTime+1;
}
int
cmp(Event a,Event b)
{
if(a.OccurTime < b.OccurTime)
return -1;
if(a.OccurTime == b.OccurTime)
return 0;
if(a.OccurTime > b.OccurTime)
return 1;
return INDEFINE;
}
Status
InitList_L(LinkList *L)
{
(*L) = (LinkList)malloc(sizeof(LNode));
if(!(*L))
exit(OVERFLOW);
(*L)->next = NULL;
return OK;
}
Status
ListEmpty_L(LinkList L)
{
if( L != NULL && L->next == NULL)
return TRUE;
else
return FALSE;
}
Status
ListDelete_L(LinkList L,int i,LElemType_L *e)
{
LinkList pre,p;
int j;
pre = L;
j = 1;
while(pre->next && j<i)
{
pre = pre->next;
++j;
}
if(!pre->next || j > i)
return ERROR;
p = pre->next;
pre->next = p->next;
*e = p->data;
free(p);
return OK;
}
Status
InitQueue_L(LinkQueue *Q)
{
(*Q).front = (*Q).rear = (QueuePtr)malloc(sizeof(QNode));
if(!(*Q).front)
exit(OVERFLOW);
(*Q).front->next = NULL;
return OK;
}
int
QueueLength_L(LinkQueue Q)
{
int count = 0;
QueuePtr p = Q.front;
while(p != Q.rear)
{
count++;
p = p->next;
}
return count;
}
Status
EnQueue_L(LinkQueue *Q,QElemType_L e)
{
QueuePtr p;
p = (QueuePtr)malloc(sizeof(QNode));
if(!p)
exit(OVERFLOW);
p->data = e;
p->next = NULL;
(*Q).rear->next = p;
(*Q).rear = p;
return OK;
}
Status
DeQueue_L(LinkQueue *Q,QElemType_L *e)
{
QueuePtr p;
if( (*Q).front == (*Q).rear )
return ERROR;
p = (*Q).front->next;
*e = p->data;
(*Q).front->next = p->next;
if((*Q).rear == p)
(*Q).rear = (*Q).front;
free(p);
return OK;
}
Status
QueueEmpty_L(LinkQueue Q)
{
if(Q.front == Q.rear)
return TRUE;
else
return FALSE;
}
Status
GetHead_L(LinkQueue Q,QElemType_L *e)
{
QueuePtr p;
if(Q.front == Q.rear)
return ERROR;
p = Q.front->next;
*e = p->data;
return OK;
}
int
Minimum()
{
int i1 = QueueLength_L(gQ[1]);
int i2 = QueueLength_L(gQ[2]);
int i3 = QueueLength_L(gQ[3]);
int i4 = QueueLength_L(gQ[4]);
if( i1<=i2 && i1<=i3 && i1<=i4 )
return 1;
if( i2<i1 && i2<=i3 && i2<=i4 )
return 2;
if( i3<i1 && i3<i2 && i3<=i4 )
return 3;
if( i4<i1 && i4<i2 && i4<i3 )
return 4;
return INDEFINE;
}
Status
OrderInsert(EventList gEv,Event gEn,int(cmp)(Event,Event))
{
int i;
EventList p,pre,s;
pre = gEv;
p = gEv->next; // 因为链表带头节点,所以p指向第一个事件
while(p && cmp(gEn,p->data) == 1) //查找事件gEn在时间表中插入的位置
{
pre = p;
p = p->next;
}
s = (LinkList)malloc(sizeof(LNode));
if(!s)
exit(OVERFLOW);
s->data = gEn;
s->next = pre->next;
pre->next = s;
return OK;
}
void
OpenForDay()
{
int i;
gTotalTime = 0;
gCustomerNum = 0;
InitList_L(&gEv);//为什么要用struct LNode ** 呀
//这里用的都是指向指针的指针!!!
//用二级指针的原因:
//一级指针作为函数参数可以交换两个数的值,
//二级指针作为函数参数可以改变一级指针的值,也就是改变地址。
gEn.OccurTime = 0;
gEn.NType = Arrive;
OrderInsert(gEv,gEn,cmp);
for(i = 1;i <= 4;i++)
{
InitQueue_L(&gQ[i]); // 同样的疑问
}
Show(); //最后再写
}
Status
MoreEvent()
{
if(!ListEmpty_L(gEv))
return TRUE;
else
return FALSE;
}
void
EventDrived(char *event)
{
ListDelete_L(gEv,1,&gEn);
if(gEn.NType == Arrive)
*event = 'A';
else
*event = 'D';
}
void
CustomerArrived()
{
int durtime,intertime;
int cur_LeftTime,suc_ArrivalTime;
int i;
++gCustomerNum;
Random(&durtime,&intertime);
cur_LeftTime = gEn.OccurTime + durtime;
suc_ArrivalTime = gEn.OccurTime + intertime;
gCustomerRcd.ArrivedTime = gEn.OccurTime;
gCustomerRcd.Duration = durtime;
gCustomerRcd.Count = gCustomerNum;
i = Minimum();
EnQueue_L(&gQ[i],gCustomerRcd); //用户加入最短的队列
Show();
if(suc_ArrivalTime < gCloseTime)
{
gEn.OccurTime = suc_ArrivalTime;
gEn.NType = Arrive;
OrderInsert(gEv,gEn,cmp);
}
if(QueueLength_L(gQ[i]) == 1)
{
gEn.OccurTime = cur_LeftTime;
gEn.NType = i;
OrderInsert(gEv,gEn,cmp);
}
}
void
CustomerDeparture()
{
int i = gEn.NType;
DeQueue_L(&gQ[i],&gCustomerRcd);
Show();
gTotalTime = gEn.OccurTime - gCustomerRcd.ArrivedTime;
if(!QueueEmpty_L(gQ[i]))
{
GetHead_L(gQ[i],&gCustomerRcd);
gEn.OccurTime += gCustomerRcd.Duration;
gEn.NType = i;
OrderInsert(gEv,gEn,cmp);
}
}
void
Invalid()
{
printf("wrong!\n");
exit(OVERFLOW);
}
void
CloseForDay()
{
printf("Today have %d customers,The Average Time is %f\n",
gCustomerNum, (float)gTotalTime / gCustomerNum);
}
void
Bank_Simulation_1()
{
char eventType;
OpenForDay();
while(MoreEvent())
{
EventDrived(&eventType);
switch(eventType)
{
case 'A':
CustomerArrived();
break;
case 'D':
CustomerDeparture();
break;
default:
Invalid();
}
}
CloseForDay();
}
void Bank_Simulation_2()
{
OpenForDay();
while(!ListEmpty_L(gEv))
{
ListDelete_L(gEv,1,&gEn);
if(gEn.NType == Arrive)
CustomerArrived();
else
CustomerDeparture();
}
}
int main(int argc, char const *argv[])
{
Bank_Simulation_1();
return 0;
}