队列
队列初识
定义:
队列是限定只能在表的一端进行插入,在表的另一端进行删除的线性表
- 队尾——允许插入的一端
- 队头——允许删除的一端
队列的特点:先进先出
队列的基本操作
由于没有定义具体的存储结构,所以这一小节仅仅介绍,下一小节依据具体存储结构实现
- 队列的初始化:
InitQueue(&Q)
初始条件:队列Q不存在
操作结果:构造一个空的队列 - 叛队空的操作:
QueueEmpty(Q)
初始条件:队列Q已存在
操作结果:若Q为空队列,则返回TRUE,否则返回FALSE - 入队操作:
EnEmpty(&Q,e)
初始条件:队列Q已存在
操作结果:插入元素e为Q的新的队尾元素 - 出队操作:
DeQueue(&Q,&e)
初始条件:Q为非空队列
操作结果:删除Q的队头元素,并用e返回其值 - 读取队头元素:
GetHead(Q,&e)
初始条件:Q为非空队列
操作结果:用e返回Q的队头元素
队列的存储
链队列——链式映像
链式映像的结点结构定义:
typedef struct QNode { //结点类型
QElemType data;
strcut QNode *next;
}QNode,*QueuePtr;
typedef struct //链队列类型
{
QueuePtr front; //队头指针
QueuePtr rear; //队尾指针
}LinkQueue;
LinkQueue Q;
为了操作方便我们给链队列添加一个头结点,并令头指针指向头结点
构造一个空队列:
Status InitQueue(LinkQueue &Q) {
//构造一个空队列
Q.front = Q.rear = (QueuePtr)malloc(sizeof*(QNode));
if(!Q.front)
exit(OVERFLOW); //存储分配失败
Q.front->next = NULL;
}
销毁链队列:
Status DestroyQueue (LinkQueue &Q) {
while(Q.front) {
Q.rear = Q.front->next;
free(Q.front);
Q.front = Q.rear;
}
return OK;
}
判断队列是否为空:
Status QueueEmpty (LinkQueue Q){ //判队列是否为空
return (Q.front==Q.rear);
}
求链队列的队头元素:
status GetHead(LinkQueue Q,QElemType &e) {
if(Q.front == Q.rear)
return ERROR;
e = Q.front->next->data;
return OK;
}
插入元素e为Q的新的队尾元素:
Status EnQueue(LinkQueue &Q,QELemType e) {
p = (QueuePtr)malloc(sizeof*(QNode));
if(!p)
exit(OVERFLOW); //存储分配失败
p->data = e;
p->next = NULL;
Q.front->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;
}
循环队列——顺序映像
引入循环
队列的顺序存储结构是使用一维数组实现的
存在的问题:
设数组长度为M,则:
- 当front=0,rear=M时,再有元素入队发生溢出——真溢出
- 当front不等于0,rear= M时,再有元素队列发生溢出——假溢出
解决方案:
1、 队首固定,每次出队剩余向下移动——浪费时间
2、循环队列:
- 基本思想:把队列设想成环形,让sq[0]接在sq[M-1]之后,若rear+1 == M,则令rear=0
循环队列
实现:利用模运算
队满队空的条件都是front=rear,怎么区分:
1、另外设置一个标志以区分队满队空
2、少用一个元素空间,此时:
- 队空:front == rear
- 队满:(rear+1)%M == front
- 入队:q [rear] = x; rear = (rear+1)%M;
- 出队:x = =q[front];front = (front+1) % M;
循环队列的类型定义:
#define MAXQSIZE 100 //最大队列长度
typedef struct {
QElemType *base; //动态分配内存空间
int front; //头指针 若队列不为空 指向队列头元素
int rear; //尾指针,若队列不空 指向队列尾元素的下一个位置
}SqQueue;
构造一个空队列Q:
Status InitQueue(SqQueue &Q) {
//构造一个空队列Q
Q.base = (QElemType*)malloc(MAXQSIZE*sizeof(QElemType));
if(!Q.base)
exit(OVERFLOW);
Q.front = Q.rear = 0;
return OK;
}
插入元素e为Q的新的队尾元素:
Status EnQueue(SqQueue &Q,ElemType e) {
if((Q.rear+1)%MAXQSIZE == Q.front)
return ERROR; //队列满
Q.base[Q.rear] = e;
Q.rear = (Q.rear+1)%MAXQSIZE;
return OK;
}
求循环队列的长度:
int QueueLength(SqQueue Q) {
return (Q.rear - Q.front + MAXQSIZE)%MAXQSIZE;
}
删除队头元素:
Status DeQueue(SqQueue &Q,QElemType &e) {
if(Q.rear == Q.front)
return ERROR;
e = Q.base[Q.front];
Q.front = (Q.front+1)%MAXQSIZE;
return OK;
}