循环队列的实现(附完整代码)

题目解读

在这里插入图片描述
本题是要求我们设计一个循环的队列,循环队列要有以下功能:
1.获取队首元素,若队列为空返回-1
2.获取队尾元素,若队列为空,则返回-1
3.插入元素,插入成功返回真
4.删除元素,删除成功返回真
5.检查队列是否为空
6.检查队列是否已满
首先我们可以将之前写的用链表实现的队列的代码拷贝到该题中,以便于循环队列的实现,然后开始构思。
循环队列的解释题目中也给出了解释:
循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”

解题构思

所以我们可以把循环队列先画图,他是一个环形的队列,并且首位相连尾接
在这里插入图片描述
那么,循环队列什么时候是满的,什么时候是空的呢?
其实,当队首和队尾在同一个位置时,这个时候队列就是空的,而当对头front的位置等于对尾rear的位置加1时,这个时候队列就是满的:
在这里插入图片描述
经过前面的构思,这个题目就很好理解了
但是还有一个问题很值得思考:
题目中对于循环队列的定义还有一个点很重要:
循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。
什么意思呢?

也就是说,循环队列中我们如果在栈满了之后还想存储值,也是可以的,但是就要反复地使用之前用过的空间,会将其覆盖,所以尾指针rear和头指针front的位置的下标是会有覆盖的变化的

我们将循环队列形象地转换成数组:
在这里插入图片描述

这样你就能理解我上面所说的问题了!
你可以看到,队列为空时,按照题目的意思,front的位置时为rear+1的,在上图中,其实front的位置是0,rear的位置是3。
他们之间的关系就需要我们来求证一下了,因为在循环队列这个环形队列中,无论插入还是删除,都是从队头(或者是队尾)进行操作的!
我们其实就可以发现front的位置是与队列最大存储元素有关联的,上图中最大存储个数是3,当front存入4个元素时,存完第3个就满了,这个时候就应该重新从front位置开始存储,所以front(rear)和存储个数k有着以下关系:
在这里插入图片描述
就是说无论front的位置怎么移动,他最终都是在1-k的范围之内的

front  =  front  %  ( k + 1 )

现在,我们就可以开始用代码实现循环队列:

循环队列的构造

我们首先定义一个结构体,就是循环队列的结构
首先就是front和rear分别为队首和队尾的下标位置
然后就是k,存储元素个数
还有数组a,存储元素

typedef struct 
{int front;int rear;int k;int* a;
} MyCircularQueue;

然后我们就可以构造一个循环队列了

MyCircularQueue* myCircularQueueCreate(int k) 
{MyCircularQueue* obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));obj->a=(int*)malloc(sizeof(int)*(k+1));obj->front=obj->rear=0;obj->k=k;return obj;
}
判断循环队列是否为空

我们在前面的解题构思中就知道,当front和rear相等时,循环队列就为空了,所以我们直接返回obj->front==obj->rear,如果队列为空,就返回 1,队列不为空就返回0

bool myCircularQueueIsEmpty(MyCircularQueue* obj) 
{return obj->front==obj->rear;
}
判断循环队列是否已满

当rear+1和front相等时就是满的
这里能这样写吗?答案是不能,他要除以k+1然后取余,和front的方法一样

bool myCircularQueueIsFull(MyCircularQueue* obj) 
{return (obj->rear+1)%(obj->k+1)==obj->front;
}
循环队列插入元素

如果队列已经满了我们就直接返回false即可
如果不是满的话就要将数组rear位置下标的值赋值为你要插入的元素的值
同时rear++,然后取余,最后返回true

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) 
{if(myCircularQueueIsFull(obj)){return false;}obj->a[obj->rear]=value;obj->rear++;obj->rear %= (obj->k+1);return true;
}
循环队列删除元素

当队列为空时就不能删了,返回-1
不为空时,我们就将front的位置往前移动,这样队首的元素就被删除了
同时记得取余

bool myCircularQueueDeQueue(MyCircularQueue* obj) 
{if(myCircularQueueIsEmpty(obj)){return false;}obj->front++;obj->front %= (obj->k+1);   return true;
}
获取循环队列队首元素

这个也很简单,直接返回数组的front下标位置的元素即可

int myCircularQueueFront(MyCircularQueue* obj) 
{if(myCircularQueueIsEmpty(obj)){return -1;}return obj->a[obj->front];
}
获取循环队列尾首元素

返回队尾元素我们就要根据图来具体求下标的关系了
由于画图较为麻烦,作者水平很有限,故不画图,给上源码,诸位大佬自己琢磨

int myCircularQueueRear(MyCircularQueue* obj) 
{if(myCircularQueueIsEmpty(obj)){return -1;}return obj->a[(obj->rear+obj->k)%(obj->k+1)];
}
循环队列的销毁

free循环队列目标的同时记得把数组也给free掉,不然可能会出现内存泄漏

void myCircularQueueFree(MyCircularQueue* obj) 
{free(obj->a);free(obj);
}

完整代码如下:

typedef struct 
{int front;int rear;int k;int* a;
} MyCircularQueue;MyCircularQueue* myCircularQueueCreate(int k) 
{MyCircularQueue* obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));obj->a=(int*)malloc(sizeof(int)*(k+1));obj->front=obj->rear=0;obj->k=k;return obj;
}bool myCircularQueueIsEmpty(MyCircularQueue* obj) 
{return obj->front==obj->rear;
}bool myCircularQueueIsFull(MyCircularQueue* obj) 
{return (obj->rear+1)%(obj->k+1)==obj->front;
}bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) 
{if(myCircularQueueIsFull(obj)){return false;}obj->a[obj->rear]=value;obj->rear++;obj->rear %= (obj->k+1);return true;
}bool myCircularQueueDeQueue(MyCircularQueue* obj) 
{if(myCircularQueueIsEmpty(obj)){return false;}obj->front++;obj->front %= (obj->k+1);   return true;
}int myCircularQueueFront(MyCircularQueue* obj) 
{if(myCircularQueueIsEmpty(obj)){return -1;}return obj->a[obj->front];
}int myCircularQueueRear(MyCircularQueue* obj) 
{if(myCircularQueueIsEmpty(obj)){return -1;}return obj->a[(obj->rear+obj->k)%(obj->k+1)];
}void myCircularQueueFree(MyCircularQueue* obj) 
{free(obj->a);free(obj);
}

好了,今天的分享到这里就结束了,谢谢大家的支持!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/217796.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

生物动力葡萄酒和有机葡萄酒一样吗?

农业维持了数十万年的文明,但当人类以错误的方式过多干预,过于专注于制造和操纵产品时,农业往往会失败。如果我们的目标是获得最高质量的收成,并长期坚持我们的做法,我们就必须与土地打交道。 当我们开始寻找生物动力…

鲁棒优化入门(4)-两阶段鲁棒优化及行列生成算法(CCG)超详细讲解(附matlab代码)

本文的主要参考文献: Zeng B , Zhao L . Solving Two-stage Robust Optimization Problems by A Constraint-and-Column Generation Method[J]. Operations Research Letters, 2013, 41(5):457-461. 1.两阶段鲁棒优化问题的引入 鲁棒优化是应对数据不确定性的一种优…

带你用uniapp从零开发一个仿小米商场_1.环境搭建

uniapp 介绍 uni-app 是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可发布到iOS、Android、Web(响应式)、以及各种小程序(微信/支付宝/百度/头条/飞书/QQ/快手/钉钉/淘宝)、快应用等多个…

阿里云windwos 安装oracle数据库,外部用工具连接不上,只能在服务器本机通过127.0.0.1 连接

1. 首先检查阿里云服务器安全组端口是否开放 oracle 数据库端口 2. 其次找到oracle 安装的目录,打开这俩个文件,将localhost 修改为 服务器本机名称 3.重启oracle 监听服务,就可以连接了

24年天津天狮专升本计算机科学与技术专业《C语言程序设计》考纲

2024年天津天狮学院计算机科学与技术专业高职升本入学考试《C语言程序设计》考试大纲 一、考试性质 《C语言程序设计》专业课程考试是天津天狮学院计算机科学与技术专业高职升本 入学考试的必考科目之一,其性质是考核学生是否达到了升入本科继续学习的要求而进行的…

接口测试场景:怎么实现登录之后,需要进行昵称修改?

在接口测试中有一个这样的场景:登录之后,需要进行昵称修改,怎么实现? 首先我们分别看下登录、昵称修改的接口说明: 以上业务中补充一点,昵称修改,还需要添加请求头Authorization传登录获取的to…

redis基本数据结构(String,Hash,Set,List,SortedSet)【学习笔记】

redis数据结构介绍 redis是一个key-value的数据库,key一般是String类型,但是value的类型多种多样。 redis 通用命令 keys : 查看符合模板的所有key (keys partten ,匹配表达式支持一些特殊字符 * ?)del:删…

测试Bard和ChatGPT对双休有关法规的认知和简单推理

Bard是试验品,chatgpt是3.5版的。 首先带着问题,借助网络搜索,从政府官方网站等权威网站进行确认,已知正确答案的情况下,再来印证两个大语言模型的优劣。 想要了解的问题是,在中国,跟法定工作…

【Linux】gcc和g++

👦个人主页:Weraphael ✍🏻作者简介:目前正在学习c和Linux还有算法 ✈️专栏:Linux 🐋 希望大家多多支持,咱一起进步!😁 如果文章有啥瑕疵,希望大佬指点一二 …

Golang并发模型:Goroutine 与 Channel 初探

文章目录 goroutinegoexit() channel缓冲closerangeselect goroutine goroutine 是 Go 语言中的一种轻量级线程(lightweight thread),由 Go 运行时环境管理。与传统的线程相比,goroutine 的创建和销毁的开销很小,可以…

无线网络下VMWare+CentOS7使用桥接模式无法联通网络问题

因为最近新配了台带无线网卡的主机,所以准备把所有的内容都转移到新电脑上,其中就包括虚拟机 安装好VMWareCentOS7选择桥接模式 然后我们去修改一下网络配置 cd /etc/sysconfig/network-scripts/进入这个ifcfg-ens33文件 我们修改箭头所示内容&#xff…

毅速丨3D打印随形水路为何受到模具制造追捧

在模具制造行业中,随形水路镶件正逐渐成为一种革命性的技术,其提高冷却效率、优化产品设计、降低成本等优点,为模具制造带来了巨大的创新价值。 随形水路是一种根据产品形状定制的冷却水路,其镶件可以均匀地分布在模具的表面或内部…