详解循环队列
定义
循环队列是一种特殊的队列,它使用有限的存储空间来实现队列的操作。循环队列将队列的尾部和头部相连,形成一个环状的逻辑空间,使得队列的头部和尾部可以循环使用存储空间。在循环队列中,当存储空间的最后一个位置已被使用而再要进入队运算时,只需要存储空间的第一个位置空闲,便可将元素加入到第一个位置,即将存储空间的第一个位置作为队尾。循环队列可以更简单防止伪溢出的发生,但队列大小是固定的。
特点
循环队列的特点主要包括:
- 高效利用存储空间,通过循环利用存储空间来减少浪费。
- 防止伪溢出,循环队列的设计可以避免伪溢出的发生。
- 固定的队列大小,循环队列的大小是固定的,不能动态调整。
- 队头和队尾指针,循环队列需要维护两个指针来跟踪队头和队尾元素的位置。
- 先进先出(FIFO),循环队列遵循先进先出原则,先进入的元素先出队。
- 时间复杂度,循环队列的插入和删除操作的时间复杂度为O(1)。
队列的运算
初始化
这段代码是C语言中循环队列的初始化函数,它接收一个指向循环队列结构体的指针作为参数。在函数体中,将队列的头指针和尾指针都初始化为0,表示队列初始时为空。函数返回值为0,表示函数执行成功。
c
/*循环队列初始化*/
int init(CirclesQueue *Q)
{
Q->front = Q->rear = 0;
return 0;
}
入队
这段代码是C语言中循环队列的入队操作函数。它首先检查队列是否已满,如果已满则输出错误信息并返回10003,如果未满则将数据插入到队列尾部并返回0。
c
/*入队*/
int enqueue(CirclesQueue *Q, DataType x)
{
if(isfull(Q))
{
printf("队列已满!10003\n");
return 10003;
}
Q->rear = (Q->rear+1) % MAXSIZE;
Q->data[Q->rear] = x;
return 0;
}
出队
这段代码是C语言中循环队列的出队操作函数。它首先检查队列是否为空,如果为空则输出错误信息并返回10003,如果非空则将队列头部的数据赋值给*x
并返回0。
c
/*出队*/
int dequeue(CirclesQueue *Q, DataType *x)
{
if(isempty(Q))
{
printf("队列为空!10003\n");
return 10003;
}
Q->front = (Q->front+1) % MAXSIZE;
*x = Q->data[Q->front];
return 0;
}
队空?
这段代码是C语言中判断循环队列是否为空的函数。如果循环队列的头指针和尾指针相等,则队列为空,函数返回1;否则,队列不为空,函数返回0。
c
/*队空*/
int isempty(CirclesQueue *Q)
{
return (Q->front == Q->rear) ? 1 : 0;
}
队满
这段代码是C语言中判断循环队列是否已满的函数。如果循环队列的尾指针加1后对最大容量取模等于头指针,则队列已满,函数返回1;否则,队列未满,函数返回0。
c
/*队满?*/
int isfull(CirclesQueue *Q)
{
return (Q->rear+1)%MAXSIZE == Q->front ? 1 : 0;
}
队内元素个数
这段代码是C语言中获取循环队列大小的函数。如果队列未满,则返回队列中元素数量。如果队列已满,则返回队列能够容纳的元素数量。
c
/*队内元素个数*/
int getsize(CirclesQueue *Q)
{
int size;
if(Q->rear > Q->front){
printf("%d ",Q->rear - Q->front);
size = Q->rear - Q->front;
} else if(Q->rear < Q->front){
printf("%d ",MAXSIZE - (Q->front - Q->rear));
size = MAXSIZE - (Q->front - Q->rear);
}
return size;
}
队首元素
这段代码是C语言中获取循环队列头部的函数。如果队列为空,则输出错误信息并返回10003;否则,获取头部元素值并赋值给*x
,然后返回0。
c
/*队首元素*/
int getfront(CirclesQueue *Q, DataType *x)
{
if(isempty(Q)){
printf("队列为空!10003\n");
return 10003;
}
int i;
i = (Q->front+1) % MAXSIZE;
*x = Q->data[i];
return 0;
}
输出队列
这段代码是C语言中打印循环队列中所有元素的函数。如果队列为空,则输出错误信息;否则,循环遍历队列并打印每个元素的值。
c
/*输出队列*/
void print(CirclesQueue *Q)
{
int i;
if(isempty(Q))
{
printf("队列为空!\n");
return;
}
printf("队内所有元素为:");
i = (Q->front) % MAXSIZE;
do{
printf(" %d", Q->data[(i + 1) % MAXSIZE]);
i = (i + 1) % MAXSIZE;
} while (i != Q->rear);
}
队列的实现
完整代码
项目结构
bash
main.c
CirclesQueue.c
CirclesQueue.h
项目文件
main.c
c
#include <stdio.h>
#include "CirclesQueue.h"
int main(int argc, char* argv[])
{
CirclesQueue Q;
DataType x;
int cmd;
char yn;
do
{
printf("-----------循环队列演示-----------\n");
printf(" 1. 初始化\n");
printf(" 2. 入队\n");
printf(" 3. 出队\n");
printf(" 4. 队空?\n");
printf(" 5. 队满\n");
printf(" 6. 队内元素个数\n");
printf(" 7. 队首元素\n");
printf(" 8. 输出循环队列所有元素\n");
printf(" 9. 帮助\n");
printf(" 0. 退出\n");
printf(" 请选择(0~9):");
scanf("%d",&cmd);
switch(cmd)
{
case 1:
init(&Q);
printf("队列已初始化!\n");
break;
case 2:
printf("请输入要入队的元素x=");
scanf("%d", &x);
if(!enqueue(&Q,x))
{
printf("元素x=%d已入队\n", x);
}
break;
case 3:
printf("确定要出队(出队会将删除对首元素, y or n, n)?");
// flushall();
getchar();
scanf("%c", &yn);
if(yn == 'y' || yn == 'Y')
{
if(!dequeue(&Q,&x))
{
printf("队首元素【%d】已出队!\n", x);
}
}
break;
case 4:
if(isempty(&Q)){
printf("队列为空,还可以添加元素哦!\n");
break;
}
printf("队列有元素\n");
break;
case 5:
if(isfull(&Q)){
printf("满了哦!可以选择出队哦!\n");
break;
}
printf("队列还未满,还可以添加元素哦!\n");
break;
case 6:
printf("队列长度为:%d \n",getsize(&Q));
break;
case 7:
// getfront(&Q);
if(!getfront(&Q, &x)){
printf("队首元素为:%d\n", x);
}
break;
case 8:
print(&Q);
break;
case 9:
printf("本程序为顺序栈的演示程序,由付雄宇靓仔设计开发。\n对该文章有疑问欢迎交流!\n");
}
}while(cmd!=0);
return 0;
}
CirclesQueue.c
c
/*
CirclesQueue.c
*/
#include "CirclesQueue.h"
/*循环队列初始化*/
int init(CirclesQueue *Q)
{
Q->front = Q->rear = 0;
return 0;
}
/*入队*/
int enqueue(CirclesQueue *Q, DataType x)
{
if(isfull(Q))
{
printf("队列已满!10003\n");
return 10003;
}
Q->rear = (Q->rear+1) % MAXSIZE;
Q->data[Q->rear] = x;
return 0;
}
/*队满?*/
int isfull(CirclesQueue *Q)
{
return (Q->rear+1)%MAXSIZE == Q->front ? 1 : 0;
}
/*出队*/
int dequeue(CirclesQueue *Q, DataType *x)
{
if(isempty(Q))
{
printf("队列为空!10003\n");
return 10003;
}
Q->front = (Q->front+1) % MAXSIZE;
*x = Q->data[Q->front];
return 0;
}
/*队空*/
int isempty(CirclesQueue *Q)
{
return (Q->front == Q->rear) ? 1 : 0;
}
/*队内元素个数*/
int getsize(CirclesQueue *Q)
{
int size;
if(Q->rear > Q->front){
printf("%d ",Q->rear - Q->front);
size = Q->rear - Q->front;
} else if(Q->rear < Q->front){
printf("%d ",MAXSIZE - (Q->front - Q->rear));
size = MAXSIZE - (Q->front - Q->rear);
}
return size;
}
/*队首元素*/
int getfront(CirclesQueue *Q, DataType *x)
{
if(isempty(Q)){
printf("队列为空!10003\n");
return 10003;
}
int i;
i = (Q->front+1) % MAXSIZE;
*x = Q->data[i];
return 0;
}
/*输出队列*/
void print(CirclesQueue *Q)
{
int i;
if(isempty(Q))
{
printf("队列为空!\n");
return;
}
printf("队内所有元素为:");
i = (Q->front) % MAXSIZE;
do{
printf(" %d", Q->data[(i + 1) % MAXSIZE]);
i = (i + 1) % MAXSIZE;
} while (i != Q->rear);
}
CirclesQueue.h
c
/*
CirclesQueue.h
循环队列
*/
#define MAXSIZE 5
typedef int DataType;
typedef struct
{
DataType data[MAXSIZE];
int front;
int rear;
}CirclesQueue;
/*循环队列初始化*/
int init(CirclesQueue *Q);
/*入队*/
int enqueue(CirclesQueue *Q, DataType x);
/*队满?*/
int isfull(CirclesQueue *Q);
/*出队*/
int dequeue(CirclesQueue *Q, DataType *);
/*队空*/
int isempty(CirclesQueue *Q);
/*队内元素个数*/
int getsize(CirclesQueue *Q);
/*队首元素*/
int getfront(CirclesQueue *Q, DataType *x);
/*输出队列*/
void print(CirclesQueue *Q);
运行结果
小结
循环队列是一种特殊类型的队列数据结构,它使用数组实现,并能够循环利用空间。在循环队列中,队尾和队头之间形成了一个循环,当队尾指针追上队头指针时,队列不再增长,而是继续利用之前出队的空间。循环队列通常由两个指针来辅助构建:队尾指针指向队尾元素的下一个位置,也就是即将插入新元素的位置;队头指针指向队头元素的位置。
循环队列的入队和出队操作是这样的:入队操作会将元素插入到队尾指针所指向的位置,并将队尾指针后移。当队列满时,入队操作会失败。出队操作会删除队头元素,并将队头指针后移。当队列为空时,出队操作会失败。队空和队满的条件是:当队列为空时,队头指针和队尾指针同时指向下标为0的位置;队列满的条件是队尾指针加1等于队头指针。循环队列需要预留一个空间来区分队列为空和队列满的状态,所以队列满的条件是队尾指针加1等于队头指针。