数据结构学习,队列篇(顺序队和循环队列)

563 阅读6分钟

这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战

前言:

之前我们把栈学完了,比较简单,今天我们学习队列里面的顺序队和循环队列,说难不难,说简单不简单,我们需要认真学习,博主会尽力把原理和逻辑讲明白,不懂的童鞋可以认真多看几遍,博主真的很想教会大家。希望大家认真看,有问题的地方可以评论提出来,希望大家,喜欢。

每日一遍,防止早恋:

20160924702204_GNWiCZ

1.什么是队列

队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。队列的数据元素又称为队列元素。在队列中插入一个队列元素称为入队,从队列中删除一个队列元素称为出队。因为队列只允许在一端插入,在另一端删除,所以只有最早进入队列的元素才能最先从队列中删除,故队列又称为先进先出FIFO—first in first out)线性表。

1.1认识顺序队列,理解逻辑

顺序队列是队列的顺序存储结构,顺序队列实际上是运算受限的顺序表。和顺序表一样,顺序队列用一个向量空间来存放当前队列中的元素。由于队列的队头和队尾的位置是变化的,设置两个指针frontrear分别指示队头元素和队尾元素在向量空间中的位置,它们的初值在队列初始化时均应设置为0。讲人话就是(一个数组有两个标志,一个在头,一个在尾,头负责输出值,尾负责输入值这两个值最大值就是MaxSize)大致就是这样,在生活中我们学习任何东西,都需要学习它逻辑,才能理解这个东西的含义,方便我们记忆,画一个简单的生活图给大家理解一下

image-20211103165631486

不知道大家有没有喝过茶颜悦色,博主是在长沙的在校大学生,这边茶颜悦色,特别火,每次博主有时间去外面玩会点一杯茶颜悦色,每次去博主就是那个队尾,那个可怜的家伙,去喝茶颜悦色每次都要排队,等博主到队头了,博主就会发现我后面就每没人了,卑微,点一杯“少年时”或者“幽兰拿铁”,你会发现,你还要等,等他出奶茶,这时候你会发现你之前的人也在等而且在你前面,还得排队,哈哈哈,当你喝到的时候会发现等待是值得的。(队列就相当于我们生活中的排队,先来的先买,后来的要排队,等队头买完)。顺序队列比较简单就是头尾自增,然后不管是头还是尾退出条件都是等于MaxSize,可以直接用循环队列的代码来表达顺序表,因为循环队列的最大值(sq.front+1)%MaxSize和MaxSize就小了1,我们就不演示了,重点是循环队列。

1.2理解循环队列,认识我们需要的代码

为充分利用向量空间,克服"假溢出"现象的方法是:将向量空间想象为一个首尾相接的圆环,并称这种向量为循环向量。存储在其中的队列称为循环队列(Circular Queue)。循环队列是把顺序队列首尾相连,把存储队列元素的表从逻辑上看成一个环,成为循环队列。

image-20211103163744973

相当于一直在这个队列里面转,可以很方便的节省空间

#define MaxSize 20 //我们队列最大存储个数
typedef struct
{
	int data[MaxSize];
	int front,rear;
}SqQueue;//循环队列是类型
sq.rear =sq.front = 0;//初始化队列头尾
(sq.rear+1)%MaxSize==sq.front//这个是出队时发现队满了往上溢出,只要我们进队了,就可以接着往初始的地方出队
sq.rear==sq.front//这句就是队空往下溢出
sq.rear = (sq.rear+1)%MaxSize;//进队模除相当于循环进一,就相当于往后偏离了一个位置满了就会到队头因为模除
*x =sq.data[(sq.front+1)%MaxSize];//出队模除和进队一样的道理

上面就是循环队列核心代码。

1.3 循环队列初始化

typedef struct
{
	int data[MaxSize];//定义队列空间大小
	int front,rear;//队头和队尾
}SqQueue;
void InitQueue(SqQueue &sq)
{
	sq.rear =sq.front = 0;//初始化
}
int GetHead(SqQueue sq,int *x)//获取队头的值
{
	if(sq.rear==sq.front)//队空
	{
			return 0;
	}
	*x =sq.data[(sq.front+1)%MaxSize];//取队头的值
	return 1;
}

1.4循环队列入队

int EnQueue(SqQueue &sq,int x)//入队
{
	if((sq.rear+1)%MaxSize==sq.front)//判断队满
	{
			return 0;
	}
	sq.rear = (sq.rear+1)%MaxSize;//就相当于往上偏离了一个位置满了就会到初始的位置,因为模除循环
	sq.data[sq.rear] = x;//把值写入
	return 1;
}

1..5循环队列出队

int DeQueue(SqQueue &sq,int *x)
{
	if(sq.rear==sq.front){//判断队空
			return 0;
	}
	sq.front = (sq.front+1)%MaxSize;//就相当于往下偏离了一个位置满了就会到初始的位置因为模除
	*x =sq.data[sq.front];
	return 1;
}

1.6 循环队列效果演示和整体代码

image-20211103171732056

image-20211103171938707

#include <stdio.h>
#include <stdlib.h>
#define MaxSize 6

typedef struct
{
	int data[MaxSize];
	int front,rear;
}SqQueue;
void InitQueue(SqQueue &sq)
{
	
	sq.rear =sq.front = 0;
}
int EnQueue(SqQueue &sq,int x)
{
	if((sq.rear+1)%MaxSize==sq.front)
	{
			return 0;
	}

	sq.rear = (sq.rear+1)%MaxSize;
	sq.data[sq.rear] = x;
	return 1;
}

int DeQueue(SqQueue &sq,int *x)
{
	if(sq.rear==sq.front){
			return 0;
	}
	sq.front = (sq.front+1)%MaxSize;
	*x =sq.data[sq.front];
	return 1;
}
int GetHead(SqQueue sq,int *x)
{
	if(sq.rear==sq.front)
	{
			return 0;
	}
	*x =sq.data[(sq.front+1)%MaxSize];
	return 1;
}
int QueueEmpty(SqQueue sq)
{
	if(sq.rear==sq.front)return 1;
	return 0; 
}
int main(int argc, char *argv[]) {
	SqQueue sq; 
	int e;
	int i,n,m,num;
	printf("初始化队列\n");
	InitQueue(sq);
	if(QueueEmpty(sq)==1)
	{
		printf("队空\n");
	 } 
	 else{
	 	printf("队不空\n"); 
	 }
	 printf("输入你需要入队的个数(不超过MaXSize:%d)\n",MaxSize);
	 scanf("%d",&n);
	  printf("输入你的%d的值:",n);
	 for(i=0;i<n;i++)
	 {
	 	scanf("%d",&num);
	 	if(EnQueue(sq,num))
	 	{
	 		printf("%d入队成功\n",num);
		 }
		 else{
		 	printf("%d入队失败可能队满了\n",num);
		 }
		 if(i==4){
		 	DeQueue(sq,&e);
	 		printf("出队:%3d\n",e);//队满的时候出一个就又可以进队一个,顺序表是不可以的 
		 }
	 }
	  GetHead(sq,&e);
	 printf("入队完成,队头的值为:%d\n",e);
	 printf("输入出队个数(不超过%d个数)\n",n);
	 scanf("%d",&m);
	 printf("出队的值:") ;
	 for(i=0;i<m;i++)
	 {
	 	if(DeQueue(sq,&e)==1)
	 	{
	 		printf("%3d",e);
	  }
		else
		{
			printf("队空");
		 }
	 }
	return 0;
}

注意:博主的代码不是用指针所以会报错,需要改为.cpp文件,才可以,或者你改指针然后用”->“访问

image-20211103162027696

总结:

其实队列难度还好和栈有异曲同工之处,只要我们理解了逻辑了,写出来是很容易的,前提是你的知道代码意思,知道代码意思才能用代码来写出你的逻辑,循环队列就是相当于转动的存储器,像生活的水管两头连接,然后里面的水不停的转动。创作不易,点赞,关注,评论,收藏,谢谢啦。不给就哭给你看!!!
上一篇:# 数据结构专升本学习,栈篇(链式栈)
下一篇:# 数据结构专升本学习,队列篇(链式队列)
6a04b428gy1fzyazadafpg20dw0din0p