数据结构学习笔记——顺序存储结构实现循环队列

Posted 晚风(●•σ )

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构学习笔记——顺序存储结构实现循环队列相关的知识,希望对你有一定的参考价值。

目录

一、循环队列的定义

前面讲到在通过顺序存储结构来判断顺序队列是否为满队时,提及到会存在“假溢出”现象,这里就可以通过循环队列来解决。

所谓循环队列,也就是将顺序队列中的一维数组首尾相连成环,也就是在逻辑上视为一个环连接起来,其存储类型定义与顺序队列的存储类型定义是一样的,也是定义数组data[MaxSize]和两个指针,即队头指针front指向队头元素,队尾指针rear指向队尾元素,如下:

#define MaxSize 20
//循环队列的定义
typedef struct 
	int data[MaxSize];
	int front,rear;	//队头指针和队尾指针
 SqQueue;

例如下图是个空循环队列,其中data[]数组中未存任何数据元素,指针front、rear都指向同一位置,此时队列为空:

二、循环队列的初始化

循环队列的初始化与顺序队列的初始化代码一样,当Q.front=Q.rear=0时,表示循环队列的初始状态,此时队列为空,如下代码:

//循环队列的初始化
void InitQueue(SqQueue &Q) 
	Q.front=Q.rear=0;	//队头指针和队尾指针d都指向0

三、判断循环队列是否为空队

循环队列的判空代码与顺序队列也是一样,当判断顺序队列是否为空队时,可以判断队头指针front和队尾指针rear是否相等,即if条件语句为Q.front==Q.rear,如下代码:

//判断循环队列是否为空队
bool EmptyQueue(SqQueue Q)
	if(Q.front==Q.rear)	//当队头指针front等于队尾指针rear时队列为空 
		return true;
	else
		return false;

四、判断循环队列是否为满队

判断循环队列是否为满队就要另外写代码,由于我们采用循环队列实现队列,我们规定:牺牲一个存储单元来区分是否满队,入队时少使用一个队列单元,即队头指针在队尾指针的下一个位置时,此时作为满队的条件,如下图:

这里我们可以知道,我们定义的MaxSize=7,即data[MaxSize],采用“%”取余符号,来定义每次入队、出队和判断队列是否为满队的代码逻辑,假定x为数字,MaxSize已知为7,即x%7的所有可能性为0、1、2、3、4、5、6,我们可以通过利用这一点来使队头指针和队尾指针判断和进行某些操作时更方便。
以下给出判断循环队列为满队的判断条件:

if((Q.rear+1)%MaxSize==Q.front)
	return true;

直接通过代码可能无法理解,以下会在入队和出队操作时细讲从而明白,即这里的代码意思就是当队尾指针进1与MaxSize取余的值等于头指针时,此时队列已满,如下:

我们可知当前队头指针Q.front=1,Q.rear=0,即(Q.rear+1)%MaxSize=(0+1)%7=1%7=1,等于Q.front=1,所以此时队列为满队,此时队头指针在队尾指针的下一个位置。

五、入队(插入操作)

前面已经规定入队时少使用一个队列单元,我们可以得出,每次入队操作时,也就是首先判断队列是否为满队,然后先送值到队列的末尾,然后再将队尾指针Q.rear加1取模(通过%实现)。

执行一次入队操作,送数据元素的值“A”(从队尾插入,先进先出),队尾指针Q.rear移动加1,如下:

入队的代码依然是通过取余运算实现,队尾指针加1,即Q.rear=(Q.rear+1)%MaxSize,我们知道不管前面(Q.rear+1)为多少,它与MaxSize(图示中MaxSize=5)取余的结果只可能是0、1、2、3、4,也就是队尾指针Q.rear的每次移动加1。

//入队(插入操作)
bool EnterQueue(SqQueue &Q,int x)
	if((Q.rear+1)%MaxSize==Q.front)	//若队列为满,则报错 
		return false;
	Q.data[Q.rear]=x;	//送入入队数据元素x的值 
	Q.rear=(Q.rear+1)%MaxSize;	//队尾指针加1取模 
	return true;

六、出队(删除操作)

每次出队操作时,也就是首先判断队列是否为空队,然后先取队列的队头元素,然后再将队头指针Q.front加1取模(通过%实现)。

执行一次出队操作,先取队头元素“A”(A位于队头,先进先出),然后再队头指针Q.front移动加1,如下:

出队的代码依然是通过取余运算实现,队头指针加1,即Q.front=(Q.front+1)%MaxSize,我们知道不管前面(Q.front+1)为多少,它与MaxSize(图示中MaxSize=5)取余的结果只可能是0、1、2、3、4,也就是队头指针Q.front的每次移动加1。

//出队(删除操作)
bool PopQueue(SqQueue &Q,int x) 
	if(Q.front==Q.rear)	//若队列为空,则报错 
		return false;
	x=Q.data[Q.front];	//取出队头数据元素x的值 
	Q.front=(Q.front+1)%MaxSize;	//队头指针加1取模 
	return true;

七、读取循环队列队头元素

读取循环队列队头元素首先判断队列是否为空,然后也是通过取余操作,取当前队头指针Q.front所指的数据元素,代码如下:

//读取循环队列队头元素
bool GetHeadQueue(SqQueue Q,int &x)  
	if(Q.front==Q.rear)	//若队列为空,则报错 
		return false;
	x=Q.data[(Q.front)%MaxSize];
	return true;

八、循环队列的遍历输出

循环队列的遍历输出首先判断队列是否为空,然后与顺序队列的遍历输出代码一样,也是通过一个while循环,循环条件是当队头指针小于队尾指针时一直执行下去,然后每次取队头指针所指的数据元素,之后再加1,从而输出每个数据元素,代码如下:

//循环队列的遍历输出
bool PrintQueue(SqQueue Q,int x) 
	if(Q.front==Q.rear)	//若队列为空,则报错 
		return false;
	while(Q.front<Q.rear) 
		x=Q.data[Q.front++];
		printf("%d ",x);
	
	return true;

九、循环队列的数据元素个数

首先判断队列是否为空,然后通过队尾指针减队头指针加上MaxSize的值与MaxSize取余,即可得到数据元素个数,代码如下:

//循环队列的数据元素个数
bool NumQueue(SqQueue Q)
	if(Q.front==Q.rear)	//若队列为空,则报错 
		return false;
	int num=(Q.rear-Q.front+MaxSize)%MaxSize;
	printf("当前循环队列的数据元素个数为:%d\\n",num);

十、循环队列的建立

顺序队列的建立程序代码与顺序队列是一样的,通过输入一个值表示要创建的顺序队列的元素个数,然后通过一个for循环建立顺序队列,其中每次通过队列的入队操作,从而向队列中输入数据元素并插入至队列中,代码如下:

//循环队列的建立
void CreateQueue(SqQueue &Q,int x) 
	int number;
	printf("请输入要建立的队列元素个数:\\n");
	scanf("%d",&number);
	for(int i=0; i<number; i++) 
		printf("输入第%d个入队的元素:\\n",i+1);
		scanf("%d",&x);
		EnterQueue(Q,x);
	

❤️循环队列的完整代码

循环队列的完整代码如下:

#include<stdio.h>
#define MaxSize 20
//循环队列的定义
typedef struct 
	int data[MaxSize];
	int front,rear;	//队头指针和队尾指针
 SqQueue;

//循环队列的初始化
void InitQueue(SqQueue &Q) 
	Q.front=Q.rear=0;	//队头指针和队尾指针d都指向0


//判断循环队列是否为空队
bool EmptyQueue(SqQueue Q)
	if(Q.front==Q.rear)	//当队头指针front等于队尾指针rear时队列为空 
		return true;
	else
		return false;


//判断循环队列是否为满队
bool FullQueue(SqQueue Q)
	if((Q.rear+1)%MaxSize==Q.front)
		return true;
	else
		return false;


//入队(插入操作)
bool EnterQueue(SqQueue &Q,int x)
	if((Q.rear+1)%MaxSize==Q.front)	//若队列为满,则报错 
		return false;
	Q.data[Q.rear]=x;	//送入入队数据元素x的值 
	Q.rear=(Q.rear+1)%MaxSize;	//队尾指针加1取模 
	return true;


//出队(删除操作)
bool PopQueue(SqQueue &Q,int x) 
	if(Q.front==Q.rear)	//若队列为空,则报错 
		return false;
	x=Q.data[Q.front];	//取出队头数据元素x的值 
	Q.front=(Q.front+1)%MaxSize;	//队头指针加1取模 
	return true;


//读取循环队列队头元素
bool GetHeadQueue(SqQueue Q,int &x)  
	if(Q.front==Q.rear)	//若队列为空,则报错 
		return false;
	x=Q.data[(Q.front)%MaxSize];
	return true;


//循环队列的遍历输出
bool PrintQueue(SqQueue Q,int x) 
	if(Q.front==Q.rear)	//若队列为空,则报错 
		return false;
	while(Q.front<Q.rear) 
		x=Q.data[Q.front++];
		printf("%d ",x);
	
	return true;


//循环队列的数据元素个数
bool NumQueue(SqQueue Q)
	if(Q.front==Q.rear)	//若队列为空,则报错 
		return false;
	int num=(Q.rear-Q.front+MaxSize)%MaxSize;
	printf("当前循环队列的数据元素个数为:%d\\n",num);


//循环队列的建立
void CreateQueue(SqQueue &Q,int x) 
	int number;
	printf("请输入要建立的队列元素个数:\\n");
	scanf("%d",&number);
	for(int i=0; i<number; i++) 
		printf("输入第%d个入队的元素:\\n",i+1);
		scanf("%d",&x);
		EnterQueue(Q,x);
	

一个简单的循环队列的基本实现例子

例如,创建一个循环队列,其初始数据为1,5,7,3,首先遍历输出该队列,然后读取队头元素,此时输出当前循环队列的数据元素个数,执行一次入队操作,入队元素为6,此时读取当前的队头元素,执行一次出队操作,此时再读取当前的队头元素,最后遍历输出当前队列。

代码如下:

#include<stdio.h>
#define MaxSize 20
//循环队列的定义
typedef struct 
	int data[MaxSize];
	int front,rear;	//队头指针和队尾指针
 SqQueue;

//循环队列的初始化
void InitQueue(SqQueue &Q) 
	Q.front=Q.rear=0;	//队头指针和队尾指针d都指向0


//判断循环队列是否为空队
bool EmptyQueue(SqQueue Q)
	if(Q.front==Q.rear)	//当队头指针front等于队尾指针rear时队列为空 
		return true;
	else
		return false;


//判断循环队列是否为满队
bool FullQueue(SqQueue Q)
	if((Q.rear+1)%MaxSize==Q.front)
		return true;
	else
		return false;


//入队(插入操作)
bool EnterQueue(SqQueue &Q,int x)
	if((Q.rear+1)%MaxSize==Q.front)	//若队列为满,则报错 
		return false;
	Q.data[Q.rear]=x;	//送入入队数据元素x的值 
	Q.rear=(Q.rear+1)%MaxSize;	//队尾指针加1取模 
	return true;


//出队(删除操作)
bool PopQueue(SqQueue &Q,int x) 
	if(Q.front==Q.rear)	//若队列为空,则报错 
		return false;
	x=Q.data[Q.front];	//取出队头数据元素x的值 
	Q.front=(Q.front+1)%MaxSize;	//队头指针加1取模 
	return true;


//读取循环队列队头元素
bool GetHeadQueue(SqQueue Q,int &x)  
	if(Q.front==Q.rear)	//若队列为空,则报错 
		return false;
	x=Q.data[(Q.front)%MaxSize];
	return true;


//循环队列的遍历输出
bool PrintQueue(SqQueue Q,int x) 
	if(Q.front==Q.rear)	//若队列为空,则报错 
		return false;
	while(Q.front<Q.rear) 
		x=Q.data[Q.front++];
		printf("%d ",x);
	
	return true;


//循环队列的数据元素个数
bool NumQueue(SqQueue Q)
	if(Q.front==Q.rear)	//若队列为空,则报错 
		return false;
	int num=(Q.rear-Q.front+MaxSize)%MaxSize;
	printf("当前循环队列的数据元素个数为:%d\\n",num);


//循环队列的建立
void CreateQueue(SqQueue &Q,int x) 
	int number;
	printf("请输入要建立的队列元素个数:\\n");
	scanf("%d",&number);
	for(int i=0; i<number; i++) 
		printf("输入第%d个入队的元素:\\n",i+1);
		scanf("%d",&x);
		EnterQueue(Q,x);
	


//主函数
int main() 
	SqQueue Q;
	int x,e;
	InitQueue(Q);	//初始化
	CreateQueue(Q,x);	//创建队列
	printf("遍历输出当前队列元素:\\n");
	PrintQueue(Q,x);	//遍历输出队列
	printf("\\n");
	GetHeadQueue(Q,x);	//读取队列的队头元素
	printf("读取队列的队头元素,当前队头元素为:%d\\n",x);
	NumQueue(Q);
	printf("请输入一个要入队的元素:");
	scanf("%d",&e);
	EnterQueue(Q,e);	//入队操作 
	GetHeadQueue(Q,x);
	printf("读取队列的队头元素,当前队头元素为:%d\\n",x);
	NumQueue(Q);
	PopQueue(Q,x);	//出队操作 
	GetHeadQueue(Q,x);
	printf("执行一次出队操作后,当前队头元素为:%d\\n",x);
	printf("遍历输出当前队列元素:\\n");
	PrintQueue(Q,x);	//遍历输出队列

运行结果如下:

以上是关于数据结构学习笔记——顺序存储结构实现循环队列的主要内容,如果未能解决你的问题,请参考以下文章

数据结构学习笔记——队列的基本知识和顺序存储结构实现队列(顺序队列)

数据结构学习笔记——队列的基本知识和顺序存储结构实现队列

如何只用队头指针实现顺序循环队列?

Redis学习笔记~实现消息队列比MSMQ更方便

求一个完整的C程序验证顺序存储结构--循环队列的基本操作

数据结构学习笔记(栈队列)整理与总结