本文主要讲述的是循环队列。为什么会有循环队列这种东西呢?循环队列出现是为了充分利用向量空间,克服“假上溢”现象。所谓“假上溢”现象是指:由于入队和出队操作中,头尾指针只增加不减小,致使被删元素的空间永远无法重新利用。当队列中实际的元素个数远远小于向量空间的规模时,也可能由于尾指针已超越向量空间的上界而不能做入队操作此时称作“假上溢”。在这里有几个问题需要注意一下:
首先,头尾指针的加1操作需要与非循环队列的顺序队列区分开来。具体是用的是“模运算”来处理。其次,队空和队满时头尾指针均相等,所以不能通过头尾指针是否相等来判断对空。本文采用的方法是:使用一个计数器记录队列中元素的总数(即队列长度),从而帮助判断队空和队满。最后,需要说明的是,也可以通过数组来模拟循环队列,具体代码思想与本文的代码部分相同,就不再给出了,请读者自己写出。本文的错误之处,还请指出!
#include<cstdio>
#define QueueSize 100 //假定预分配的循环队列空间最多为100个元素
typedef char Datatype; //假定循环队列元素的数据类型为字符
typedef struct {
Datatype data[QueueSize];
int front; //头指针,队非空时指向队头元素
int rear; //尾指针,队非空时指向队尾元素的下一位置
int count; //计数器,记录队中元素总数
}CirQueue;
//********************************循环队列的一些基本操作**********************************
void InitQueue(CirQueue *Q){
//将循环队列置空
Q->front=Q->rear=0;
Q->count=0; //计数器置0
}
int QueueEmpty(CirQueue *Q){
//判断循环队列是否为空,若为空,则返回真,否则返回假
return Q->count==0; //队列无元素为空
}
int QueueFull(CirQueue *Q){
//判断循环队列是否满了,若满了则返回真,否则返回假
return Q->count==QueueSize; //队中元素个数等于QueueSize时队满
}
void EnQueue(CirQueue *Q,Datatype x){
//进循环队列操作
if(QueueFull(Q)){
printf("Queue overflow\n"); //队满上溢,退出运行
return ;
}
Q->count++; //队列元素个数加1
Q->data[Q->rear]=x; //将新元素插入队尾
Q->rear=(Q->rear+1)%QueueSize; //循环意义下将队尾指针加1
}
void DeQueue(CirQueue *Q){
//出循环队列操作
if(QueueEmpty(Q)){
printf("Queue underflow\n"); //队空下溢,退出运行
return ;
}
Q->count--; //队列元素个数减1
Q->front=(Q->front+1)%QueueSize; //将队头指针加1
}
Datatype QueueFront(CirQueue *Q){
//取循环队列顶元素
if(QueueEmpty(Q)){ //循环队列空则无法取循环队列队首元素
printf("Queue is empty!\n");
return '?';
}
return Q->data[Q->front];
}
void CreateQueue(CirQueue *Q){
//建立一个循环队列
char ch;
while((ch=getchar())!='\n'){
EnQueue(Q,ch);
}
return ;
}
//***********************************测试函数********************************
int main(){
CirQueue *Q;
InitQueue(Q);
printf("输入一个字符串,来建立一个字符串循环队列:\n");
CreateQueue(Q);
printf("循环队列已建好!\n");
printf("循环队列队头元素是:%c\n",QueueFront(Q));
printf("弹出循环队列队头元素:\n");
DeQueue(Q);
printf("此时循环队列队头元素为:%c\n",QueueFront(Q));
printf("将元素‘z’入队:\n");
EnQueue(Q,'z');
printf("此时队头元素是:%c\n",QueueFront(Q));
return 0;
}
测试样例: