数据结构-循环队列(C语言描述)

前言

座右铭:talk is easy,show me the code.
我们生活在幸福的时代,我们都站在巨人的肩膀上看世界

队列

我们可以把队列想象成一个排队的过程,先去排队的先服务,也即是“先进先出”。

队列的分类

1.链式队列
2.循环队列
也就是队列的实现可以用两种方式实现,一种是用链表实现,另外一种是利用数组实现,今天我们只讲解如何利用数组实现。

循环队列

入队:排队的时候又来一个人排队。类似于你现在要去食堂排队买食物,你需要排列在队列的最后面。
出队:正在排队的人得到服务,服务完成离开队列。类似于你买食物完成,离开队列去食用。
首先我们先抛出一个观念:用数组实现的队列必然是循环队列,如果不是这样的,那么出队过的数组单元因为再无法利用而浪费掉了。

定义循环队列的结构体

#define MAX 5//表示队列最大长度
//实际上最大可容纳元素为MAX-1,后面我们会讲到
typedef struct Node
{
	int *p;
	int front;//指向队列第一个元素
	int rear;//指向队列最后一个元素的后一个空间
} Queue,*PQueue;

假如现在队列有三个元素,如图所示front,和rear的指向
在这里插入图片描述
我们初始化r让 rear=0,front=0;
我们可能理所当然觉得
入队的时候:rear=rear+1;
出队的时候:front=front+1;

但是这样没有考虑到可以对出队之后数组空间的利用。如下图所示:
在这里插入图片描述
所以,
入队:rear=(rear+1)%数组的长度
出队:front=(front+1)%数组的长度

队列为空或者为满的情况

显然,当rear=front=0的时候队列为空,当队列先入队,再出队,队列为空,此时rear=front=1,依次类推,我们可以得出结论 当rear=front的时候,队列为空

观察下图,我们可能不假思索的认为 当rear=front的时候队列为满。这时候可能就会出现歧义,当rear=front既可以是队列为满,也可以是队列为空,显然这样是不行的。
在这里插入图片描述
这样有两种方法解决,一种是定义一个变量,来记录队列中有多少个元素,但是我们通常不使用这种方法。我们通常使用另外一种方法,当(rear+1)%数组长度=front 的时候,数组满了。这样做有一个弊端,就是可以利用的数组空间是 数组长度-1 。
因此,数组长度为5,队列满的情况之一为下图
在这里插入图片描述
此时 (rear+1)%5=front,队列为满,数组长度为5,可是只存放了4个元素,但是当数组长度足够大的时候,循环链表的这个缺点几乎可以被忽略。

用代码实现队列

队列的初始化

申请动态内存,指定数组的大小,初始化front和rear,使之都指向数组下标为0位置

void init_queue(PQueue pq)
{
	pq->p=(int *)malloc(MAX*sizeof(int)); 
	pq->front=0;
	pq->rear=0;
}

入队

为了示程序更加健壮,定义了bool full_queue(PQueue pq)函数,用来判断队列是否满了

//判断队列是否满了
bool full_queue(PQueue pq)
{
	if((pq->rear+1)%MAX==pq->front)
	return true;//队列满
	else false;//没有满
}
//向队列里面写入入队元素的值
bool en_queue(PQueue pq,int val)
{
	if(full_queue(pq))
	{
		return false;
	}
	else
	{
		pq->p[pq->rear]=val;
		pq->rear=(pq->rear+1)%MAX;
		return true;
	}
}

出队

为了示程序更加健壮,定义了bool empty_queue(PQueue pq))函数。用来判断队列是否为空

//判断队列是否为空
bool empty_queue(PQueue pq)
{
	if(pq->rear==pq->front)
	{
		return true;//队列空
	}
	else return false;
	//队列没有空
}
//出队,指针用来传递即将出队元素的值
bool out_queue(PQueue pq,int *val)
{
	if(empty_queue(pq))
	{
		return false;
	}
	else
	{
		*val=pq->p[pq->front];
		pq->front=(pq->front+1)%MAX;
	}
}

遍历队列

将队列里面所有的元素,从队首到队尾依次输出。

void travarse_queue(PQueue pq)
{
	int i=pq->front;
	while(i!=pq->rear)
	{
		printf("%d  ",pq->p[i]);
		i=(i+1)%MAX;
	}
	printf("\n");
}

结果演示

我们把上述函数通过放进主函数看一下效果

```c
int main()
{
	Queue Q;
	int i;
	init_queue(&Q);
	en_queue(&Q,1);//1号元素入队
	en_queue(&Q,2);
	en_queue(&Q,3);
	en_queue(&Q,4);
	en_queue(&Q,5);
	travarse_queue(&Q);
	//输出所有元素
	if(out_queue(&Q,&i))
	//如果队列不为,显示出队元素
	{
		printf("出队成功:%d\n",i);
	}
	
	travarse_queue(&Q);
	return 0;
} 

输出结果:
在这里插入图片描述

结语

理解了队列为空和为满的情况,循环队列自然迎刃而解。

个人博客:https:xuwenxiang666.github.io
欢迎你的到来

由于水平有限,本博客难免有不足,恳请各位不吝赐教!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值