队列

1.队列的定义

  • 队列是一种先进先出的线性表。一端允许插入一端允许删除,允许插入的那端称为队尾,允许删除的那端称为对头
    在这里插入图片描述

2.队列的实现:链队列

在这里插入图片描述

  • 队列的定义
typedef int ElemType;
typedef struct QNode
{
	ElemType data;
	QNode* next;
}QNode,*Queueptr;
typedef struct
{
	Queueptr front; //队头指针
	Queueptr rear;  //对尾指针
}LinkQueue;
  • 初始化队列
bool InitQueue(LinkQueue &queue)
{
	queue.front = queue.rear = (Queueptr)malloc(sizeof(QNode));
	if(queue.front) return false;
	queue.front->next = nullptr;
	return true;
}
  • 摧毁队列
bool DestroyQueue(LinkQueue &Q)
{
	while(Q.front)
	{
		Q.rear = Q.front->next;
		free(Q.front);
		Q.front = Q.rear;
	}
	return true;
}
  • 进队列
bool EnQueue(LinkQueue& Q,ElemType e)
{
	Queueptr newNode = (Queueptr)malloc(sizeof(QNode));
	newNode->data = e;
	newNode->next = nullptr;
	Q.rear->next = newNode;
	Q.rear = newNode;
	return true;
}
  • 出队列
bool DeQueue(LinkQueue& Q,ElemType& e)
{
	//队列为空则返回
	if(Q.front->Q.rear) return false; 
	Queueptr p = Q.front->next;
	e = p->data;
	Q.front->next = p->next;
	//如果删除后为空队列,需要调整尾指针
	if(p==Q.rear)
		Q.rear = Q.front;
	free(p);
}

3.循环队列——队列的顺序表示和实现

  • 顺序表示和实现队列优势在于不用离散的分配内存节省内存方便管理,缺点是如果使用顺序表示普通队列导致头指针和尾指针不停地向前进,直到内存溢出,所以使用循环队列就很好的解决了问题
  • 在顺序表示中也是头指针指向对尾,尾指针指向队伍尾的下一个指针,rear-front为队列大小。
    在这里插入图片描述
  • rear=front表示空队列,所以满队列不能用rear=front表示,解决办法是用rear+1 = front,即实际大小是maxsize-1
  • 循环队列定义
#define MAXQSIZE 100
typedef int ElemType;
typedef struct
{
	ELenType* base;
	int front;
	int rear;
}CQueue;
  • 循环队列初始化
bool InitQueue(CQueue q)
{
	q.base = (ElemType*)malloc(sizeof(ElemType));
	if(!q.base) return;
	q.front = q.rear = 0;
}
  • 循环队列长度
bool QueueLength(Queue Q)
{
	return (Q.rear-Q.front+MAXQSIZE) % MAXQSIZE;
}
  • 进循环队列
bool EnQueue(Queue& Q,ElemType e)
{
	//如果队列满了
	if((Q.rear+1) % MAXQSIZE)==Q.front) return false;
	Q.base[rear] = e;
	Q.rear = (Q.rear+1) % MAXQSIZE;
	return true;
}
  • 出循环队列
 bool DeQueue(Queue& Q,ElemType e)
 {
 	//队列空
 	if(Q.front ==Q.rear) return false;
 	e = Q.base[Q.front];
	Q.front = (Q.front+1)%MAXQIZE;
	return true;
 }

4.队列应用之离散事件

  • 假设某银行有4个窗口对外接待客户,从早晨银行开门起不断有客户进入银行。由于每个窗口在某个时刻只能接待一个客户,因此在客户人数众多时需在每个窗口前顺次排队,对于刚进入银行的客户,如果某个窗口的业务员正空闲,则可上前办理业务;反之,若4个窗口均有客户所占,他便会排在人数最少的队伍后面。现在需要编制一个程序以模拟银行的这种业务活动并计算一天中客户在银行逗留的平均时间
  • 我们称客户到达银行和离开银行这两个时刻发生的事情为“事件”,则整个模拟程序将按事件发生的先后顺序进行处理,这样一种模拟程序称为事件驱动模拟。
  • 银行事件驱动模拟程序的定义
void Bank_Simulation(int CloseTime)
{
	OpenForDay();   //初始化
	while(MoreEvent)
	{
		EventDrived(OccurTime,EventType)  //时间驱动
		switch(EventType)
		{
			case 'A':  //处理客户到达事件
				CustomerArrivee();
				break;
			case 'D':  // 处理客户离开事件
			CustomerArrived();
			break;
			default:Invalid();
		}
	}
	CloseForDay();  //计算平均逗留时间
}
  • 需要的数据类型
typedef struct
{
	int OccurTime;  //事件发生时刻
	int NType;      //事件类型,0表示到达事件,1至4表示四个窗口的离开事件
}Event,ElemType;
typedef LinkList EventList; //事件链表类型,定义为有序链表
typedef struct
{
	int ArrivalTime; //到达时刻
	int Duration;    //办理事务所需时间
}QElemType;          //队列的数据元素类型
  • 银行事件驱动模拟程序方法的实现:
//程序中用到的主要变量
EventList ev;    //事件表
Event     en;    //事件
LinkQueue  q[5];   //4个客户队列
QElemType  customer;   //客户记录
int cmp(Event a,Event b);
{
	if(a.OccurTime>a.OcurrTime)
		return 1;
	else if(a.OccurTime==a.OcurrTime)
	 	return 0;
	else
		return -1;
}

void OpenForDay()
{
	//初始化操作
	TotalTime = 0;CustomerNum=0;
	InitList(ev); //初始化事件链表为空表
	en.OccurTime = 0; //设定第一个客户到达事件
	en.NType = 0;
	for(int i=1;i<=4;++i)
		InitQueue(q[i]);   //初始化队列
}

void CustomerArrived()
{
	++CustomerNum;
	Random(durtime,intertime);  //生成随机数
	t = en.OcurrTime + intertime; //下一客户到达时刻
	if(t<CloseTime)
		OrderInsert(ev,(t,0),cmp);
	i = Minnum(q);  //求长度最短队列
	EnQueue(q[i],(en.OccurTime,durtime));
	if(QueueLength(q[i])==1)
		OrderInsert(en,(en.OccurTime+durtime,i),cmp);  //设定第i队列的一个离开事件并插入事件表
}

void CustomerDepature()
{
	i = en.NType;
	DelQueue(q[i],customer);  //删除第i队列的排头客户
	TotalTime +=en.OccurTime-customer.ArrivalTime;
	if(!QueueEmpty(q[i]))
	{
		GetHead(q[i],customer);
		OrderInsert(ev,(en.OccurTime+curtomer.Duration,i),(*cmp)());
	}
}

void Bank_Simulation(int CLoseTime)
{
	OpenForDay();
	while(!ListEmpty(ev))
	{
		DelFirst(GetHead(ev,p);
		en = GetCurElem(p);
		if(en.NType==0)
			CustomerArrived();
		else
			CustomerDeparture();  
	}
	cout<<(float)TotalTime/CustomerNum):
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值