队列(queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线性表,就是 一种先进先出(First In,First Out)的线性表,简称FIFO。因为其特殊性,在没用链表队列的情况下,也就是顺序存储,用两个变量来记录队列头和队列尾,一端记录出列(front),一端记录入列(rear),正常情况下它的数据长度会在front的更新下不断变小,当队列已满的情况下,rear指向的位置也不能在更新了。
rear再往外就是非法内存了,队列这样肯定不行,就跟坐公交车一样,你上来的晚,后面没位置了,前排还有一个位置,你就不坐了,那也不可能啊。所以把队列想象成公交车一样,前排坐完坐后排,后排坐完前排有空位就坐前面。所以,循环队列就秉着不浪费资源的前提下诞生了。
我们把队列的这种头尾相接的顺序存储结构称为循环队列。这队列还是那么大,但是再出列的时候,空出来的位置又可以入列了。
这时候,又有一个问题了,怎么判断队列空和队列满,因为队列满和队列空front和rear在同一个位置,这就使我们不知道队列是空还是满了,所以我们怎么判断队列是空还是满呢?
办法一就是设置标志位,当front = rear ,flag = 0时,队列为空,当front = rear,flag = 1时,队列满。办法二,就是我们自己更新队满条件,当front = rear时,队列为空。当队列满时,保留一个元素空间,也就是队列虽然还剩下最后一个空闲单元,但也是满的。
主要来说一下方法二,队列满的时候,rear绕了整整一圈,设队列最长长度为MAX_QUEUE,(rear + 1)% MAX_QUEUE == front,取余就是为了避免rear 和front谁大谁小的问题。队列中的元素个数就是rear-front+MAX_QUEUE(对着图比比就出来了)。
//创建一个循环队列
//队列为空:rear == front
//队列为满:(rear + 1)%MAX_QUEUE = front
//front和rear更新方法
//front = (front + 1) % MAX_QUEUE
//rear = (rear + 1) % MAX_QUEUE
想通就好了
数据类型:
#define MAX_QUEUE 10 //队列的最长长度
typedef int DataType;
typedef struct Queue
{
DataType buf[MAX_QUEUE]; //队列长度
int front; //队列头的位置
int rear; //队列尾的位置
}SqQueue;
代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_QUEUE 10 //队列的最长长度
typedef int DataType;
typedef struct Queue
{
DataType buf[MAX_QUEUE]; //队列长度
int front; //队列头的位置
int rear; //队列尾的位置
}SqQueue;
//创建一个空的队列,并初始化
SqQueue *InitQueue()
{
SqQueue *Q = (SqQueue *)malloc(sizeof(SqQueue)); //在堆区申请地址空间
if(NULL == Q)
{
return NULL;
}
memset(Q, 0, sizeof(SqQueue)); //初始化
Q->front = 0; //新的队列,front 和 rear 都是0,表示这个队列是空的
Q->rear = 0;
return Q;
}
//判断队列是否为空
int Is_empty_Queue(SqQueue *Q)
{
return Q->front == Q->rear ? 1 : 0; //判断队列是否为空的条件是Q->front == Q->rear
}
//判断队列是否满
int Is_full_Queue(SqQueue *Q)
{
return (Q->rear + 1)%MAX_QUEUE == Q->front ? 1 : 0; //判断队列是否满了条件是(Q->rear + 1) % MAX_QUEUE = Q->front
}
//入队列
void Push_Queue(SqQueue *Q, DataType data)
{
if(Is_full_Queue(Q))
{
printf("队列为满\n");
return ;
}
Q->buf[Q->rear] = data; //将数据放在rear的位置上
Q->rear = (Q->rear + 1) % MAX_QUEUE; //更新rear
return ;
}
//出队列
void Pop_Queue(SqQueue *Q, DataType *data)
{
if(Is_empty_Queue(Q))
{
printf("队列为空\n");
return ;
}
*data = Q->buf[Q->front]; //将front位置的数赋给*data
printf("出队列的数是:%d\n",*data);
Q->front = (Q->front + 1) % MAX_QUEUE; //更新front
return ;
}
//返回Q的元素个数
int QueueLength(SqQueue *Q)
{
return (Q->rear - Q->front + MAX_QUEUE)%MAX_QUEUE;
}
//将队列清空
void ClearQueue(SqQueue *Q)
{
while(Q->front != Q->rear)
{
Q->front++;
}
}
//队列内容输出
void Printff_Queue(SqQueue *Q)
{
if(!Is_empty_Queue)
{
printf("队列已空\n");
}
int i = Q->front;
while(i % MAX_QUEUE != Q->rear)
{
printf("%d ",Q->buf[i]);
i++;
}
putchar('\n');
}
int main()
{
SqQueue *Q = InitQueue();
char buf[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
for(int i = 0;i < 10;i++)
{
Push_Queue(Q, buf[i]);
}
Printff_Queue(Q);
int len = QueueLength(Q);
printf("len = %d\n", len);
int data = 0;
Pop_Queue(Q,&data);
printf("data:%d\n", data);
Pop_Queue(Q,&data);
printf("data:%d\n", data);
// ClearQueue(Q);
Printff_Queue(Q);
return 0;
}
运行结果:
因为队列大小为10,满的时候空一个,所以9就没压进去。