详解循环队列

详解循环队列

定义

循环队列是一种特殊的队列,它使用有限的存储空间来实现队列的操作。循环队列将队列的尾部和头部相连,形成一个环状的逻辑空间,使得队列的头部和尾部可以循环使用存储空间。在循环队列中,当存储空间的最后一个位置已被使用而再要进入队运算时,只需要存储空间的第一个位置空闲,便可将元素加入到第一个位置,即将存储空间的第一个位置作为队尾。循环队列可以更简单防止伪溢出的发生,但队列大小是固定的。

特点

循环队列的特点主要包括:

  1. 高效利用存储空间,通过循环利用存储空间来减少浪费。
  2. 防止伪溢出,循环队列的设计可以避免伪溢出的发生。
  3. 固定的队列大小,循环队列的大小是固定的,不能动态调整。
  4. 队头和队尾指针,循环队列需要维护两个指针来跟踪队头和队尾元素的位置。
  5. 先进先出(FIFO),循环队列遵循先进先出原则,先进入的元素先出队。
  6. 时间复杂度,循环队列的插入和删除操作的时间复杂度为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等于队头指针。

参考文献

文心一言

相关推荐
qqxhb27 分钟前
零基础数据结构与算法——第四章:基础算法-排序(上)
java·数据结构·算法·冒泡·插入·选择
FirstFrost --sy2 小时前
数据结构之二叉树
c语言·数据结构·c++·算法·链表·深度优先·广度优先
森焱森2 小时前
垂起固定翼无人机介绍
c语言·单片机·算法·架构·无人机
搂鱼1145143 小时前
(倍增)洛谷 P1613 跑路/P4155 国旗计划
算法
Yingye Zhu(HPXXZYY)3 小时前
Codeforces 2021 C Those Who Are With Us
数据结构·c++·算法
无聊的小坏坏4 小时前
三种方法详解最长回文子串问题
c++·算法·回文串
长路 ㅤ   4 小时前
Java后端技术博客汇总文档
分布式·算法·技术分享·编程学习·java后端
秋说4 小时前
【PTA数据结构 | C语言版】两枚硬币
c语言·数据结构·算法
qq_513970445 小时前
力扣 hot100 Day37
算法·leetcode
不見星空5 小时前
leetcode 每日一题 1865. 找出和为指定值的下标对
算法·leetcode