目录
一、队列的定义
1.1相关概念
·队列是仅在表尾进行插入操作,在表头进行删除操作的线性表。
Insert(Q,n+1,x)
Delete(Q,1)
·表尾a(n)端称为队尾,表头a1端称为队头。插入元素称为"入队",删除元素称为"出队"。
·特点:先进先出
1.2队列的应用
①脱机打印输出:按申请的先后顺序依次输出
②多用户系统中,多个用户排成队,分时地循环使用CPU和主存
③按用户的优先级排成多个队,每个优先级一个队列
④实时控制系统中,信号按接收的先后顺序依次处理
⑤网络电文传输,按到达的时间先后顺序依次进行
二、队列的类型定义
ADT Queue{
数据对象:
D={ai | ai∈ElemSet,i=1,2,3....,n,n>=0}
数据关系:
R1={<a(i-1),ai> | a(i-1),ai∈D,i=2,,,,,n}
(a1为队列头,a(n)为队列尾)
基本操作:初始化、入队、出队、取队头元素等
}ADT Queue
①InitQueue(&Q) 初始化操作
操作结果:构造空队列Q
②DestroyQueue(&Q) 销毁队列操作
条件:队列Q已存在;操作结果:队列Q被销毁
③ClearQueue(&Q)清空队列操作
条件:队列Q已存在;操作结果:将Q清空
④QueueEmpty(&Q) 判断Q是否为空队列
条件:队列Q已存在;操作结果:若Q为空队列,则返回TRUE,否则返回FALSE
⑤QueueLength(&Q) 求队列的长度
条件:队列Q已存在;操作结果:返回Q的元素个数,即队列的长度
⑥GetHead(&Q) 取队头元素
条件:Q为非空队列;操作结果:用e返回Q的队头元素
⑦EnQueue(&Q) 插入队尾元素
条件:队列Q已存在;操作结果:插入元素e为Q的队尾元素
⑧DeQueue(&Q) 删除队头元素
条件:Q为非空队列;操作结果:删除Q的队头元素,用e返回值
⑨QueueTraverse(&Q) 遍历队列
条件:Q为非空队列;操作结果:依次对Q的每个数据元素进行访问
三、循环队列——队列的顺序表示和实现
3.1循环队列的定义
#define MAXQSIZE 100 //最大队列长度
Typedef struct{
QElemType *base; //初始化的动态分配存储空间
int front; //头指针,若队列不空,指向队列头元素
int rear; //尾指针,若队列不空,指向队列尾元素的下一个位置
(1)溢出问题:
设数组大小为MAXQSIZE,(数组下标为0——MAXQSIZE-1)
当rear=MAXQSIZE时,发生溢出
①若front=0,rear=MAXQSIZE时,再入队——真溢出
②front不等于0,rear=MAXQSIZE时,再入队——贾溢出
因此解决假上溢的方法——引入循环队列
原理:base[0]接在base[MAXQSIZE-1]之后,若rear+1==M,则令rear=0;
实现方法:利用模(mod,C语言中:%)运算
插入元素:Q.base[Q.rear]=x; Q.rear=(Q.rear+1)%MAXSIZE (回到0的位置)
删除元素:x=Q.base[s.front]; Q.front=(Q.front+1)%MAXSIZE (回到0的位置)
(2)判断队空或队满问题
解决方法:少用一个元素空间
队空:front=rear
队满:(rear+1)%MAXQSIZE==front
3.2循环队列的初始化
Status InitQueue(SqQueue &Q){
Q.base=new QElemType[MAXQSIZE] //分配数组空间
if(!Q.base) exit(OVERFLOW); //存储分配失败
Q.front=Q.rear=0; //头指针尾指针置为0,队列为空
return OK;
}
3.3求队列的长度
int QueueLength(SqQueue Q){
return ((Q.rear-Q.front+MAXQSIZE)%MAXQSIZE);
}
·加MAXQSIZE的原因,rear下标值可能比front小
3.4循环队列的入队
Status EnQueeu(SqQueeu &Q,QElemType e){
if((Q.rear+1)%MAXQSIZE==Q.front) return ERROR; //队满
Q.base[Q.rear]=e; //新元素加入队尾
Q.rear=(Q.rear+1)%MAXQSIZE; //队尾指针+1
return OK;
}
3.5循环队列的出队
Status DeQueue(SqQueue &Q,QElemType &e){
if(Q.front==Q.rear) return ERROR; //队空
e=Q.base[Q.front]; //保存队头元素
Q.front=(Q.front+1)%MAXQSIZE; //队头指针+1
return OK;
}
3.6取队头元素
QElemType GetHead(SqQueue Q){ //返回Q的队头元素,不修改头指针
if(Q.front!=Q.rear) //队列非空
return Q.base[Q.front]; //返回队头元素的值,队头指针不变
四、链队列——队列的链式表示和实现
4.1链队列的类型定义
#define MAXQSIZE 100 //最大队列长度
typedef struct Qnode{
QElemType data;
struct Qnode *next;
}QNode, *QueuePtr;(嵌套定义)
typedef struct{
QueeuPtr front; //队头指针
QueuePtr rear; //队尾指针
}LinkQueue;
4.2链队列运算指针变化状况
4.3链队列的初始化
Status InitQueue(LinkQueue &Q){ //构造一个空队列
Q.front=Q.rear=new QNode; //生成新结点作为头结点,队头和队尾指针指向此结点
if(!Q.front) exit(OVERFLOW);
Q.front->next=NULL; // 头指针的指针域置空
return OK;
}
4.4 链队列的销毁
(从队头结点开始,依次释放所有结点)
Status DestroyQueue (LinkQueue &Q){
while(Q.front){
p=Q.front->next; free(Q.front); Q.front=p; // Q.rear=Q.front->next; free(Q.front); Q.front=Q.rear;
}
return OK;
}
4.5链队列的入队
Status EnQueue(LinkQueue &Q,QElemType e){ //插入元素e为Q的心的队尾元素
p=new QNode; //为入队元素分配结点空间,用指针p指向
if(!p) exit(OVERFLOW);
p->data=e; //将新结点数据域置为e
p->next=NULL;Q.rear->next=p; //将新结点插入队尾
Q.rear=p; //修改队尾指针
return OK;
}
4.6链队列的出队
Status DeQueue(LinkQueue &Q,QElemType &e){ //删除Q的队头元素,用e返回其值
if(Q.front==Q.rear) return ERROR; //若队列为空,则返回ERROR
p=Q.front->next; //p指向队头元素
e=p->data; //e保存队头元素的值
Q.front->next=p->next; //修改头结点的指针域
if(Q.rear==p) Q.rear=Q.front; //最后一个元素被删,队尾指针指向头结点
delete p; //释放原队头元素的空间
return OK;
}
4.7取队头元素
Status GetHead(LinkQueue Q,QElemType &e){ //返回Q的队头元素,不修改队头指针
if(Q.front==Q.rear) return ERROR; //若队列为空,则返回ERROR
e=Q.front->next->data; //返回队头元素的值,队头指针不变(头结点的下一数据域)
return OK;
}