循环队列
循环队列
当用顺序结构实现队列时如图所示:可以用一个数组代表队列空间,队列为空时 rear和front都是指向数组第一个元素。
从队尾插入的时候可以先将队尾指向的数组赋值,再将队尾指针+1
从对头弹出元素则是先给取出元素值再将队头指针+1
但如果这么做,就会遇到一个棘手的问题,那就是队头弹出和队尾插入都是让各自指针+1,那么最终两个指针都可能到达可索引数组的最大值导致数组越界,而这时栈空间可能是空的。例如下面的当插入最后一个元素e6之后,队尾指针显然已经越界了,这时已经不能插入,但栈的空间实际还有剩余。
解决的办法是将顺序队列变成循环队列。就是让队头指针或队尾指针在当越界的那一时刻重新指向数组的开始,从而形成一个环状。可以想到的是用if语句来检测到是否达顶端然后考虑是否将指针置向初始位置。如rear++; if(rear == MAXQSIZE) rear = 0;
。但用下面这个式子显然更方便 rear = (rear+1) % MAXQSIZE;
当还没到顶时对 MAXQSIZE 取余总的到rear+1,但是当rear+1到顶时则得到0,这个结果和if实现的功能一致,但更简洁了。
完整示例代码
#include <stdio.h>
#include <stdlib.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXQSIZE 100
typedef int Status;
typedef int QElemType;
typedef struct
{
QElemType * base; /* 指向动态分配的存储空间 */
int front; /* 头指针,若队列不为空,指向队列头元素 */
int rear; /* 尾指针,若队列不为空,指向队列尾元素的下一个位置 */
}SqQueue;
/* 构造队列 */
Status InitQueue(SqQueue *Q)
{
Q->base = (QElemType*)malloc(sizeof(QElemType));
if(!Q->base)
return ERROR;
Q->front = Q->rear = 0;
return OK;
}
/* 销毁队列 */
Status DestroyQueue(SqQueue *Q)
{
if(!Q->base)
return ERROR;
free(Q->base);
Q->base = NULL;
Q->front = Q->rear = 0;
return OK;
}
/* 清空队列 */
Status ClearQueue(SqQueue *Q)
{
Q->front = Q->rear = 0;
return OK;
}
/* 判断队列是否为空 */
Status QueueEmpty(SqQueue *Q)
{
if(Q->front == Q->rear)
return TRUE;
else
return FALSE;
}
/* 返回队列长度 */
int QueueLength(SqQueue *Q)
{
/* 如果front在上面,rear在下面,差为负号+MAXQSIZE刚好,括号结果小于MAXQSIZE
* 取余后为原值,当font在下面,括号超过MAXQSIZE,但是取余后只取小于那部分 */
return (Q->rear - Q->front + MAXQSIZE) % MAXQSIZE;
}
/* 获取队头元素 */
Status GetHead(SqQueue *Q, QElemType *e)
{
if(!Q->base)
return ERROR; /* 队列不存在 */
*e = Q->base[Q->front];
return OK;
}
/* 插入元素e到队尾 */
Status EnQueue(SqQueue *Q, QElemType e)
{
if((Q->rear+1) % MAXQSIZE == Q->front)
return ERROR; /* rear刚好在front下面一个 队列满 */
Q->base[Q->rear] = e; /* 插入队尾 */
Q->rear = (Q->rear+1) % MAXQSIZE; /* 队尾+1,如果到顶取余后则又从底下开始了 */
return OK;
}
/* 从队头弹出元素 */
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,若到顶,则从0开始 */
return OK;
}
/* 从队头到队尾打印队列 */
void printQueue(SqQueue *Q)
{
int p = Q->front;
while(p != Q->rear) { /* 还又元素没打印 */
printf("%d ",Q->base[p]);
p = (p+1) % MAXQSIZE; /* p+1,若到顶,则从0开始 */
}
printf("\n");
}
int main()
{
SqQueue Queue;
SqQueue * Q = &Queue;
QElemType e;
InitQueue(Q);
EnQueue(Q,1);
EnQueue(Q,2);
EnQueue(Q,3);
EnQueue(Q,4);
printQueue(Q);
// 获取长度测试
printf("len %d\n",QueueLength(Q));
// 是否为空测试
printf("empty? %d\n",QueueEmpty(Q));
// 获取队头测试
GetHead(Q,&e);
printf("head? %d\n",e);
// 出队列测试
DeQueue(Q,&e);
printf("e %d\n",e);
printQueue(Q);
// 清空队列测试
ClearQueue(Q);
printQueue(Q);
// 销毁队列测试
DestroyQueue(Q);
return 0;
}