队列
队列
队列(queue)是一种先进先出(first in first out, FIFO)的线性表。只允许在表的一端进行插入,在另一端删除元素。
抽象数据类型定义
ADT Queue {
数据对象:D =
数据关系:R1 =
基本操作:
InitQueue(&Q); // 构建一个空队列Q
DestroyQueue(&Q); // 删除队列Q
ClearQueue(&Q); // 将Q清空
QueueEmpty(Q); // 判断队列Q是否为空
QueueLength(Q); // 队列长度
GetHead(Q, &e); // 用e返回Q的队头元素
EnQueue(&Q, e); // 插入元素e为Q的新的队尾元素
DeQueue(&Q, &e); // 删除Q的队头元素,并用e返回其值
QueueTraverse(Q, visit()); // 从队头到队尾,依次对Q的每个数据元素调用函数visit().
}ADT Queue
双端队列(deque):限定性数据结构
链队列——队列的链式表示和实现
存储结构
typedef struct QNode {
QElemType data;
struct QNode *next;
}QNode, *QueuePtr;
typedef struct {
QueuePtr front; // 队头指针
QueuePtr rear; // 队尾指针
}LinkQueue;
基本操作的函数原型说明
// 构造一个空队列Q
Status InitQueue(LinkQueue &Q);
// 销毁队列Q,Q不在存在
Status DestroyQueue(LinkQueue &Q);
// 将Q清为空队列
Status ClearQueue(LinkQueue &Q);
// 若队列Q为空队列,则返回TRUE, 否则返回FALSE
Status QueueEmpty(LinkQueue Q);
// 返回Q的元素个数,即为队列的长度
int QueueLength(LinkQueue Q);
// 若队列不空,则用e返回Q的队头元素,并返回OK;否则返回ERROR
Status GetHead(LinkQueue Q, QElemType &e);
// 插入元素e为Q的新的队尾元素
Status EnQueue(LinkQueue &Q, QElemType &e);
// 若队列不空,则删除Q的队头元素,用e返回其值,并返回OK;
Status DeQueue(LinkQueue &Q, QElemType &e);
// 从队头到队尾依次对队列Q中每个元素调用函数visit()
Status QueueTraverse(LinkQueue Q, visit());
基本操作的算法描述(部分)
Status InitQueue(LinkQueue &Q)
{
Q.front = Q.read = (QueuePtr)malloc(sizeof(QNode));
if(!Q.front) exit(OVERFLOW);
Q.front->next = NULL;
return OK;
}
Status DestroyQueue(LinkQueue &Q)
{
while(Q.front) {
Q.rear = Q.front->next;
free(Q.front);
Q.front = Q.rear;
}
return OK;
}
Status EnQueue(LinkQueue &Q, QElemType e) {
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(LinkQueue &Q, QElemType &e) {
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;
}
循环队列
必须设定一个最大队列长度。
存储结构
#define MAXQSIZE 100 // 最大队列长度
typedef struct {
QElemType *base;
int front;
int rear;
}SqQueue;
基本操作的算法描述
Status InitQueue(SqQueue &Q)
{
Q.base = (QElemType *)malloc(MAXQSIZE *sizeof(QElemType));
if(!Q.base) exit(OVERFLOW);
Q.front = Q.rear = 0;
return OK;
}
int QueueLength(SqQueue Q)
{
return (Q.rear - Q.front + MAXQSIZE) % MAXQSIZE;
}
Status EnQueue(SqQueue &Q, QElemType e)
{
if((Q.rear + 1)%MAXQSIZE == Q.front) return ERROR;
Q.base[Q.rear] = e;
Q.rear = (Q.rear + 1) % MAXQSIZE;
return OK;
}
离散事件模拟
银行排队办理业务
void Bank_Simulation(int CloseTime)
{
// 银行业务模拟,统计一天内客户在银行逗留的平均时间
OpenForDay(); // 初始化
while(MoreEvent) {
EventDrived(OccurTime, EventType); // 事件驱动
switch(EventType) {
case 'A': CustomerArrived(); break; // 处理客户到达事件
case 'D': CustomerDeparture(); break; // 处理客户离开事件
default: Invalid();
}
}
CloseForDay; // 计算平均逗留时间
}
模拟程序的实现
typedef struct {
int OccurTime; // 事件发生时刻
int NType; // 事件类型,0表示到达事件,1至4表示四个窗口的离开事件
}Event, ElemType; // 事件类型,有序链表LinkList 的数据元素类型
typedef LinkList EventList // 事件链表类型,定义为有序链表
typedef struct {
int ArrivalTime; // 到达时刻
int Duration; // 办理事务所需时间
}QElemType; // 队列的数据元素类型
EventList ev; // 事件表
Event en; // 事件
LinkQueue q[5]; // 4个客户队列
QElemType customer; // 客户记录
int TotalTime, CustomerNum; // 累计客户逗留时间,客户数
int cmp(Event a, Event b); // 依事件a的发生时刻<或=或>事件b的发生时刻分别返回-1或0或1
void OpenForDay() {
// 初始化操作
TotalTime = 0; CustomerNum = 0; // 初始化累计时间和客户数为0
InitList(ev); // 初始化事件链表为空表
en.OccurTime = 0; en.NType = 0; // 设定第一个客户达到事件
OrderInsert(ev, en, cmp); // 插入事件表
for(i=1; i<=4; ++i) InitQueue(q[i]); // 置空队列
}
void CustomerArrived() {
// 处理客户到达事件,en.NType = 0
++CustomerNum;
Random(durtime, intertime); // 生成随机数
t = en.OccurTime + intertime; // 下一客户到达时刻
if(t < CloseTime) // 银行尚未关门,插入事件表
OrderInsert(ev, (t, 0), cmp);
i = Minimum(q); // 求长度最短队列
EnQueue(q[i], (en.OccurTime, durtime));
if(QueueLength (q[i] == 1)
OrderInsert(ev, (en.OccurTime + durtime, i), cmp); // 设定第i队列的一个离开事件并插入事件表
}
void CustomerDeparture() {
// 处理客户离开事件,en.NType > 0
i = en.NType; DelQueue(q[i], customer); // 删除第i队列的排头客户
TotalTime += en.OccurTime - customer.ArrivalTime; // 累计客户逗留时间
if(!QueueEmpty(q[i])) { // 设定第i队列的一个离开事件并插入事件表
GetHear(q[i], customer);
OrderInsert(ev, (en.OccurTime + curtomer.Duration, i), (*cmp)());
}
}