18.11.24
(基于C语言,欢迎指正)
队列
是一种先进先出(FIFO)的线性表,只允许在队尾进行插入,在队首进行删除
顺序存储的队列写起来跟顺序实现的栈很像,也是采用数组存储数据,但是在不断入队列和出队列过程中,数据会不断后移,所以会造成大量的空间浪费,所以这里我们采用循环队列的形式
循环队列长度
我们需要知道,循环队列也是采用的数组的形式,并且有两个标记位置的整型变量front和rear,其中,front等于队首元素的下标,rear等于队尾元素下一个位置的下标
也就是说,开始时,循环队列长这样
此时,我们可以发现,循环队列为空,front等于rear
然后我们不断的入队列
最终,循环队列满了,长这样
我们发现front还是等于rear,于是我们无法通过front和rear判断循环队列是否满了吗?
我们可以不让他满,让他差一点满
像这样
于是,如果出现front等于rear,那么队列就是空的
那怎么判断队满呢
先假设队列最大长度为 MaxSize
MaxSize这里等于5
我们可以发现
当front>=rear
就是这样
队列的长度为rear-front=5-1=4
当front<rear
就是这样
那么此时,队列长度为rear-front+MaxSize=1-2+5=4
所以,结合上面两种情况,我们可以得出求循环队列长度的通用公式
( rear - front + MaxSize ) % MaxSize
注意这里是取余符号%,不是除法
这个公式子在写循环队列的时候会经常用到,很重要!!!
那么我们开始写循环队列
准备工作
头文件,循环队列的规模,结点的设定,老生常谈的东西了
#include<stdio.h>
#include<stdlib.h>
#define MaxSize 10 //循环队列最多有10-1=9个元素
typedef int QElemType;
typedef struct{ //对循环队列的结点的结构体进行定义
QElemType data[MaxSize];
int front; //头指针指向队首元素
int rear; //尾指针指向队尾元素的下一个位置
}SqQueue;
初始化
一开始
front=rear=0对吧
int InitQueue(SqQueue *Q){//初始化队列
Q->front=0;
Q->rear=0;
return 1;
}
队列长度
我们按照上面的公式
( rear - front + MaxSize ) % MaxSize
代码实现
int Length(SqQueue *Q){//求队列长度
int len=(Q->rear-Q->front+MaxSize)%MaxSize;
return len;
}
入队列
我们需要判断队列满的情况,即rear+1==front
代码如下
int EnQueue(SqQueue *Q,QElemType e){//入队列
if(Length(Q)+1==MaxSize){
printf("队列已满,数值%d无法进入\n",e);
return 0;
}
Q->data[Q->rear]=e;
Q->rear=(Q->rear+1)%MaxSize;//rear向后移动一位,若到最后则移动至数组头
return 1;
}
出队列
我们需要判断队列是否空,即rear!=front才能出队列
int DeQueue(SqQueue *Q,QElemType *e){//出队列,用*e保存出去的值
if(Q->rear==Q->front){
printf("队列已空,无法出队列\n");
return 0;
}
*e=Q->data[Q->front];
Q->front=(Q->front+1)%MaxSize;
return 1;
}
打印队列元素
有两种情况,如果front>rear,我们就要分段打印
void Print(SqQueue *Q){
int i=0;
printf("\n");
if(Q->front>Q->rear){
while(Q->front+i==MaxSize){
printf("%d ",Q->data[Q->front+i]);
i++;
}
i=0;
while(i!=Q->rear){
printf("%d ",Q->data[i]);
i++;
}
}
else{
i=Q->front;
while(i!=Q->rear){
printf("%d ",Q->data[i]);
i++;
}
}
printf("\n");
}
调试
一些循环队列要用到的基本函数就写完了,下面我们在主函数中进行调试
#include<stdio.h>
#include<stdlib.h>
#define MaxSize 10
typedef int QElemType;
typedef struct{ //对循环队列的结点的结构体进行定义
QElemType data[MaxSize];
int front; //头指针指向队首元素
int rear; //尾指针指向队尾元素的下一个位置
}SqQueue;
int InitQueue(SqQueue *Q){//初始化队列
Q->front=0;
Q->rear=0;
return 1;
}
int Length(SqQueue *Q){//求队列长度
int len=(Q->rear-Q->front+MaxSize)%MaxSize;
return len;
}
int EnQueue(SqQueue *Q,QElemType e){//入队列
if(Length(Q)+1==MaxSize){
printf("队列已满,数值%d无法进入\n",e);
return 0;
}
Q->data[Q->rear]=e;
Q->rear=(Q->rear+1)%MaxSize;
return 1;
}
int DeQueue(SqQueue *Q,QElemType *e){//出队列
if(Q->rear==Q->front){
printf("队列已空,无法出队列\n");
return 0;
}
*e=Q->data[Q->front];
Q->front=(Q->front+1)%MaxSize;
return 1;
}
void Print(SqQueue *Q){
int i=0;
printf("\n");
if(Q->front>Q->rear){
while(Q->front+i==MaxSize){
printf("%d ",Q->data[Q->front+i]);
i++;
}
i=0;
while(i!=Q->rear){
printf("%d ",Q->data[i]);
i++;
}
}
else{
i=Q->front;
while(i!=Q->rear){
printf("%d ",Q->data[i]);
i++;
}
}
printf("\n");
}
int main(){
int num;//要删除的元素个数
int e;//用于接收删除的元素
SqQueue Q;
InitQueue(&Q);
for(int i=0;i<12;i++){//入队列
EnQueue(&Q,i);
}
printf("队列长度为:%d \n",Length(&Q));
Print(&Q);
printf("输入要删除的元素个数(从队首进行删除)\n");
scanf("%d",&num);
for(int i=0;i<num;i++){//偷懒通过循环删除队列
if(!DeQueue(&Q,&e))
break;
printf("删除了一个元素%d,此时队列为:",e);
Print(&Q);
printf("\n");
}
printf("最终队列为:");
Print(&Q);
}
结果如下