详解循环队列(C语言版)

1循环队列的定义

循环队列是一种基于数组的队列实现方式,它通过循环利用底层数组的空间来实现队列的特性。
循环队列的定义如下:
1.队列元素以数组的形式存储,具有固定大小。
2.通过两个指针(front和rear)来标识队列的前端和后端。初始状态下,front和rear都指向队列的起始位置。
3.当往队列中添加元素时,rear指针后移,并将新元素存储在rear指针所指向的位置。若rear指针达到数组末尾,则将rear指针重新指向数组的起始位置。
4.当从队列中删除元素时,front指针后移,并将front指针所指向的元素从队列中移除。若front指针达到数组末尾,则将front指针重新指向数组的起始位置。
5.当front和rear指针相等时,表示队列为空。
6.当rear的下一个位置为front时,表示队列已满。由于需保留一个位置用于判断队列为空,实际可存储的元素数量比数组大小少1。

不仅如此,循环队列的优点是在插入和删除元素时,时间复杂度都为O(1),且可以高效利用数组空间。然而,循环队列的大小是固定的,一旦确定后就无法动态改变。此外,需要注意判断队列满和队列空的条件,以避免出现混淆。当循环队列满时,如果继续向队列中添加元素,会导致队列溢出。解决循环队列溢出的常用方法是扩容。这里我们就不介绍扩容了,想了解自己查资料哈。

2.特点

循环队列的特点有以下几个方面:
1.高效利用空间:循环队列通过循环利用底层数组的空间,避免了线性队列中的数据迁移操作。这样可以最大程度地利用底层数组的空间,提高了空间利用效率。
2.均摊时间复杂度:在循环队列中,入队和出队操作的时间复杂度均为O(1),即常数时间复杂度。这是因为循环队列通过指针的循环移动来实现入队和出队的操作,无需对整个队列进行数据搬移,从而获得了较高的时间效率。
3.可以实现循环队列的连续性:循环队列具有环形结构,通过循环利用底层数组空间的特性,可以实现队列的连续性。即使队列的前端和后端分别处于底层数组的开头和末尾,仍然可以通过正确的指针操作来实现队列的正常操作。
4.固定容量:循环队列的容量固定,一旦初始化后,无法动态改变。这是由于循环队列需要通过底层数组来存储元素,并且需要预留一个空间来区分队列为空和队列为满的情况。
5.需要额外的判断条件:为了区分队列为空和队列为满的情况,循环队列引入了一些额外的判断条件。通常使用两个指针来标识队列的前端和后端,并通过它们的相对位置来判断队列的状态。
总的来说,循环队列通过循环利用底层数组的空间、具有均摊时间复杂度的特点,以及实现队列连续性的能力,实现了一种高效的队列数据结构。它在很多应用中被广泛使用,如操作系统的进程调度、缓冲区管理等。

3.基本运算

循环队列的基本运算包括:
1.初始化队列:即创建一个空的循环队列,并分配一定大小的底层数组
2.入队操作:即向循环队列的队尾插入一个元素。首先检查循环队列是否已满,如果已满,则返回队列溢出的错误信息;如果未满,则将元素插入到队尾。
3出队操作:即从循环队列的队首删除并返回一个元素。首先检查循环队列是否为空,如果为空,则返回队列为空的错误信息;如果不为空,则将队首元素删除,并返回该元素。
4.判断队列是否为空:即判断循环队列中是否没有任何元素。通常可以通过判断指针front和rear是否相等来实现。
5.判断队列是否已满:即判断循环队列中是否已填满所有元素。可以通过判断(front + 1) % 数组长度是否等于rear来实现。
6.队列长度操作:即返回循环队列中元素的个数。
7…队列遍历操作:即遍历循环队列中的所有元素,并输出它们的值。

4.实现过程

1.这是一个循环队列的初始化操作

int init(CirclesQueue *Q)
{
	Q->front = Q->rear = 0;
	return 0;
}

2.循环队列的入队操作,使函数名为enqueue

int enqueue(CirclesQueue *Q, DataType x)
{
	if(isfull(Q))
	{
		printf("队列已满!100001\n");
		return 100001;
	}

	Q->rear = (Q->rear+1) % MAXSIZE;
	Q->data[Q->rear] = x;
	return 0;
}

3.定义了两个辅助函数:isempty和isfull,分别用于检查循环队列是否为空和是否已满

int isempty(CirclesQueue *Q)
{
	return (Q->front == Q->rear) ? 1 : 0;
}
int isfull(CirclesQueue *Q)
{
	return (Q->rear+1)%MAXSIZE == Q->front ? 1 : 0;
}

4.循环队列的出队操作,函数名为dequeue

int dequeue(CirclesQueue *Q, DataType *x)
{
	if(isempty(Q))
	{
		printf("队列为空!100002\n");
		return 100002;
	}
	Q->front = (Q->front+1) % MAXSIZE;
	*x = Q->data[Q->front];
	return 0;
}

5.定义了一个函数printQueue,用于输出循环队列的内容。

// 输出队列内容  
void printQueue(CirclesQueue *Q) {
    int i;
    if (isempty(Q)) {  
        printf("Queue is empty.\n");  
        return;  
    }  
    i = (Q -> front) %MAXSIZE;
    do{
        printf(" %d",Q -> data[(i + 1 % MAXSIZE)]);
        i = (i+1) %MAXSIZE;
    }while(i != Q -> rear);
}

6.定义一个函数getLength,用于获取循环队列的长度

// 获取队列长度  
int getLength(CirclesQueue *Q) {  
    return (Q->rear - Q->front + MAXSIZE) % MAXSIZE; // 循环队列:若rear在前方,则长度为rear-front+MAXSIZE,否则为rear-front  
}

7.定义一个函数getFront,用于获取循环队列的队首元素

// 获取队首元素  
DataType getFront(CirclesQueue* Q) {  
    int i;
    i = (Q -> front) %MAXSIZE;
    return Q -> data[(i + 1 % MAXSIZE)];
}


5.完整demo

CirclesQueue.h文件

/*
	CirclesQueue.h
	循环队列
*/

#define MAXSIZE 100

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);

// 输出队列内容  
void printQueue(CirclesQueue *Q);

// 获取队列长度  
int getLength(CirclesQueue *Q);

// 获取队首元素
DataType getFront(CirclesQueue* Q);

CirclesQueue.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("队列已满!100001\n");
		return 100001;
	}

	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("队列为空!100002\n");
		return 100002;
	}
	Q->front = (Q->front+1) % MAXSIZE;
	*x = Q->data[Q->front];
	return 0;
}

/*队空*/
int isempty(CirclesQueue *Q)
{
	return (Q->front == Q->rear) ? 1 : 0;
}

// 输出队列内容  
void printQueue(CirclesQueue *Q) {
    int i;
    if (isempty(Q)) {  
        printf("Queue is empty.\n");  
        return;  
    }  
    i = (Q -> front) %MAXSIZE;
    do{
        printf(" %d",Q -> data[(i + 1 % MAXSIZE)]);
        i = (i+1) %MAXSIZE;
    }while(i != Q -> rear);
}

// 获取队列长度  
int getLength(CirclesQueue *Q) {  
    return (Q->rear - Q->front + MAXSIZE) % MAXSIZE; // 循环队列:若rear在前方,则长度为rear-front+MAXSIZE,否则为rear-front  
} 

// 获取队首元素  
DataType getFront(CirclesQueue* Q) {  
    int i;
    i = (Q -> front) %MAXSIZE;
    return Q -> data[(i + 1 % MAXSIZE)];
}

mian.c文件

#include <stdio.h>
#include "CirclesQueue.h"
#include <string.h>
#include <stdlib.h>

int main(int argc, char* argv[])
{
	CirclesQueue Q;
	DataType x;
	int cmd;
	char yn;
int result;
    char welcome[] = "谢谢观看";
	int i = 0; 
	int n = 0;
	int m = 0; 
	
    for(i=0;i<strlen(welcome);i++)
	{
		printf("%c",welcome[i]);
		for(m=0;m<10000;m++)
			for(n=0;n<1000;n++)
			{
				;
			}
	}

	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)?");
			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");
			else printf("队列没有为空!\n");
			break;
		case 5:
			if(isfull(&Q)) printf("队列已满!\n");
			else printf("队列没有为满!\n");
			break;
		case 6:
			printf("队列的长度:%d\n",getLength(&Q));
			break;
		case 7:
		    printf("队列首元素: %d\n", getFront(&Q));  
            break;
		case 8:
			printf("输出队列:");
			printQueue(&Q);
			printf("\n");
			break;
		case 9:
		    printf("本程序为循环队列的演示程序,由柯令雄制作,\n请老师批阅,谢谢!\n");
		    break;
		}

	}while(cmd!=0);


	return 0;
}

运行结果
在这里插入图片描述

在这里插入图片描述

总结

循环队列是一种特殊的队列,与普通队列不同,使用循环队列可以有效地提高队列的效率和空间利用率,是个不错的想法,值得我们去研究!不仅如此,循环队列也是一种常用的数据结构,适用于需要快速插入、删除元素并且空间有限的场景。通过合理地管理队首和队尾指针,可以高效地使用循环队列。谢谢老师的教学!

参考文献

1.数据结构(C语言)
2.百度
3.上课的代码

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值