详解循环队列

一、循环队列的定义

环队列就是将队列存储空间的最后一个位置绕到第一个位置,形成逻辑上的环状空间,供队列循环使用。在循环队列结构中,当存储空间的最后一个位置已被使用而再要进入队运算时,只需要存储空间的第一个位置空闲,便可将元素加入到第一个位置,即将存储空间的第一个位置作为队尾。循环队列可以更简单防止伪溢出的发生,但队列大小是固定的。

二、循环队列的特点

  1. 循环队列是一种特殊的线性表,只允许在表的一端插入元素,在表的另一端删除元素。
  2. 循环队列具有队头指针和队尾指针,指示队列元素所在的位置,避免删除元素时移动大量元素。
  3. 循环队列采用先进先出(FIFO)的原则,先进入的元素先出队。
  4. 循环队列相比普通的队列,元素出队时无需移动大量元素,只需移动头指针。
  5. 循环队列适合处理用户排队等待的情况,但需要预先分配大量存储空间。

三、循环队列的运算

1、初始化

这个函数init接受一个指向CirclesQueue类型的指针Q。CirclesQueue应该是一个自定义的数据类型,它应该包含一个用于存储元素的数组以及front和rear两个整型变量。

在函数内部,我们设置Q->front = Q->rear = 0;,将front和rear都设置为0,表示队列初始时为空。

函数返回0,表示初始化成功。

/*循环队列初始化*/
int init(CirclesQueue *Q)
{
	Q->front = Q->rear = 0;
	return 0;
}

2、入队

首先,函数检查队列是否已满。如果队列已满,则打印一条消息"队列已满!100001"并返回,如果队列未满,将rear的值增加1,添加新元素到数组的末尾,在数组的尾部存储新元素x。返回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;
}

3、队满?

函数通过检查rear指向的位置是否是队列的开始位置来判断队列是否已满。如果rear指向的位置是队列的开始位置,那么队列就是满的,函数返回1;否则,函数返回0。

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

4、出队

首先,函数检查队列是否为空。如果队列为空,则打印一条消息"队列为空!100002"并返回100002。如果队列不为空,它会将队列的第一个元素删除,将x指向的变量设置为队列前部的元素,返回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;
}

5、队空?

函数通过检查front是否等于rear来判断队列是否为空。如果front等于rear,那么队列就是空的,函数返回1;否则,函数返回0。

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

6、输出队列内容

函数首先检查队列是否为空。如果队列为空,则打印"Queue is empty."并返回。如果队列不为空执行一个循环,循环条件是i != Q->rear。在循环中,打印当前front指向的元素,循环继续直到i等于rear,即已经打印了所有元素。

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

7、获取队列长度

函数通过计算Q->rear - Q->front + MAXSIZE) % MAXSIZE来获取队列的长度。这种计算方式考虑了循环队列的特性,即当rear到达数组的末尾时,它会从数组的开始位置继续。

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

8、获取队首元素

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

 四、完整代码

/*
	main.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");
			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;
}
/*
	CirclesQueue.h
	循环队列
*/

#define MAXSIZE 4

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
*/
#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("队列为空!100002\n");  
        return 100002;  
    }  
    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)];
}

 

五、运行结果

六、总结

循环队列是一种高效的数据结构,它可以避免普通队列操作时的边界检查,提高了操作的效率。在需要使用队列的数据结构问题中,循环队列是一种非常实用的选择。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值