数据结构—循环队列(环形队列)

循环队列(环形队列)

  • 循环队列的概念及结构
  • 循环队列的实现

循环队列的概念及结构

循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。

循环队列的一个好处是可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。

在这里插入图片描述
注:循环队列的空间大小是固定的

循环队列的实现

环形队列可以使用数组实现(超出数组的范围回到起始位置),也可以使用循环链表实现(尾指针的next指向头节点)。选用数组实现循环队列更好,因为数组缓存利用率更高,没有扩容的代价。

环形队列实际开辟的空间大小要比所存数据的队列长度多开辟一个空间的大小。如果环形队列实际开辟的空间大小和所存储数据个数一样时,会导致环形队列所处空的状态和满的状态是一样的。这样便无法区分。

在这里插入图片描述

因此环形队列必须多留出一个空间,这个空间不能存放数据,这样才能很好的区别环形队列的状态是空还是满。

在这里插入图片描述

在这里插入图片描述
在环形队列中,队列为空时,队头队尾指向同一个位置。当队列不为空时,队头指向插入的第一个数据,队尾指向最后一个数据的下一个位置。当tail+1等于front时,说明环形队列已满。

循环队列的定义

循环队列选择用数组实现,循环队列需要用一个指针来指向存储队列数据的空间,用两个变量来记录队列中存储数据的起始(对头)和末尾(队尾)的数组位置,最后用一个变量记录队列的存储数据的最大容量。

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

循环队列的初始化

循环队列的初始化首先创建一个循环队列,其次对该结构体的成员进行初始化即可。

MyCircularQueue* myCircularQueueCreate(int k) {MyCircularQueue* cur=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));cur->a=(int *)malloc(sizeof(int)*(k+1));cur->k=k;cur->front=0;cur->tail=0;return cur;
}

注:k表示的是设置队列的长度

循环队列的入队列

入队列操作首先要判断循环队列是否已满,如果满了则返回假;如果没满则向循环队列插入一个数据(即在tail位置放数据)然后tail向后挪动一个位置,最后返回真。

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {assert(obj);if(myCircularQueueIsFull(obj)){return false;}obj->a[obj->tail]=value;obj->tail++;obj->tail=obj->tail%(obj->k+1);return true;
}

注:tail的位置为k+1时,就需要对tail进行处理防止tail对数组进行越界访问。这也遵循了循环队列的原则,当访问到数组末尾时再次访问应该访问到数组的起始位置。

循环队列的出队列

出队列操作首先判断循环队列是否为空,如果为空了,则出队列失败返回假;如果不为空则从循环队列中删除一个元素(即只需将front往后挪一个位置即可),如果成功删除则返回真。

bool myCircularQueueDeQueue(MyCircularQueue* obj) {assert(obj);if(myCircularQueueIsEmpty(obj)){return false;}obj->front++;obj->front%=obj->k+1;return true;
}

注:当front为k+1时处理方式和入队列的tail类似。

获取循环队列的对头数据

获取循环队列的对头数据首先判断循环队列是否为空,如果为空则返回-1;如果不为空只需通过front的位置获取数组中的数据并返回该数据即可。

int myCircularQueueFront(MyCircularQueue* obj) {assert(obj);if(myCircularQueueIsEmpty(obj)){return -1;}return obj->a[obj->front];
}

获取循环队列的对尾数据

获取循环队列的对尾数据首先判断循环队列是否为空,如果为空则返回-1;如果不为空只需通过tail获取tail的前一个位置的数组中的数据并返回该数据即可。

int myCircularQueueRear(MyCircularQueue* obj) {assert(obj);if(myCircularQueueIsEmpty(obj)){return -1;}int prevtail=obj->tail-1;if(obj->tail==0){prevtail=obj->k;}return obj->a[prevtail];
}

注:当tail为0时,此时取队尾数据时取的是数组下标为k的元素数据。因为tail表示的是最后一个有效数据的下一个位置。

循环队列的判空

循环队列的判空只需判断队头和队尾是否相等即可

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {assert(obj);return obj->front==obj->tail;
}

循环队列的判满

循环队列的判满只需判断队尾的下一个位置和队头是否相等即可

bool myCircularQueueIsFull(MyCircularQueue* obj) {assert(obj);return obj->front==((obj->tail)+1)%(obj->k+1);
}

注:当tail为k时tail的下一个位置为0,此时处理情况和出入队列的处理情况类似。

循环链表的销毁

循环链表的销毁首先要对循环链表结构体中的成员进行释放,然后再对循环链表进行释放即可。

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

注意:

  • 环形队列中存储数据的空间是一开始就要创建好的,删除数据时是front指针往后走,存储数据的空间不销毁。插入数据时是往tail所指向的空间放数据,不申请空间,tail往后走。
  • 循环队列如果用链表实现最好用双向链表实现,单向链表不好去找循环队列的队尾数据,而且采用链表的形式实现需要定义节点的结构体以及在初始化方面需要创建k+1个节点并建立连接,这样操作起来很麻烦没有数组省事,因此用数组实现循环队列更好。

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

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

相关文章

多种编程语言运行速度排名-10亿次除7求余数为0的数量

最佳方式是运行10次,取平均数,用时秒数显示3位小数。 因为第一次打开,可能CPU还没优化好,多次取平均,比较准确 第1次共10次,用时3秒,平均3秒 第2次共10次,用时4秒,平均3.…

利用lammps模拟蓝宝石在水润滑环境下的抛光

一 问题描述 蓝宝石(Al2O3)由于其独特的晶体结构,优异的物理化学特性,被广泛应用于航空航天等领域。高精尖的应用领域要求蓝宝石具有纳米级的表面粗糙度以及严格可控的亚表面缺陷。影响超精密加工最终性能的因素主要集中在工件表…

学习笔记|课后练习解答|电磁炉LED实战|逻辑运算|STC32G单片机视频开发教程(冲哥)|第八集(下):课后练习分析与解答

文章目录 课后练习解答需求分解增加KEY3控制代码如下: 第一版代码问题分析Tips:STC-ISP的设置 Tips:定时器实现完整电磁炉显示功能的代码测试流程 总结 课后练习解答 增加按键3,按下后表示启动,选择的对应的功能的LED…

git Update failed cannot lock ref

报错详情 解决方案 百度了很多方案,过滤出了有效方案 去该项目下的.git文件里找到报错文件,本例中即为:.git/refs/tags/pre-RELEASE-PRE-20230817-03 删除该文件,重新pull,pull成功问题解决

淘宝免费爬虫数据 商品详情数据 商品销售额销量API

场景:一个宽敞明亮的办公室,一位公司高管坐在办公桌前。 高管(自言自语):淘宝,这个平台上商品真是琳琅满目,应该有不少销售数据吧。我该怎么利用这些数据呢? 突然,房间…

解决问题的步骤

得到曲铠的课程学习。 个人感觉前面几节如明确和理解问题,拆分问题,挺好的。 后面就是水分很大,感觉有点烂尾了。 拆分和定期问题,这个指导意义还是很大的。 本质上思路还是有很多学习的地方,更加明确了&#xff0…

多线程学习之多线程的三种实现方式及应用

一、继承Thread类 1.1方法 方法名说明void run()在线程开启后,此方法将被调用执行void start()使此线程开始执行,Java虚拟机会调用run方法() run()方法和start()方法的区别: run():封装线程执行的代码,直接调用&am…

【Jenkins】持续集成部署学习

【Jenkins】持续集成部署学习 【一】Jenkins介绍【二】Docker安装Gitlab【1】首先准备一台空的虚拟机服务器【2】安装服务器所需的依赖【3】Docker的安装【4】阿里云镜像加速【5】安装Gitlab 【三】Gitlab的使用(1)Gitlab创建项目(2&#xff…

elemenPlus ElMessage 字符串如何换行问题

因为后端返回的数据是一长串,而且带有\r,\n等换行符,但是并没有生效。前端写法: // 抛出错误ElMessage.error(msg);我们知道\r,\n,\r\n 是在不同系统下的换行符的表示,但在JavaScript返回字符串中并没有生效…

C++通过JNI调用JAVA方法返回ArrayList对象

运行效果: JAVA实现: 获取系统已安装应用列表并返回List<String>对象 //使用系统API获取安装包列表public List<String> getAppList(MainActivity act) {List<String> packages = new ArrayList<String>();try {//取包信息列表List<PackageInf…

js实现定时器

用原生js实现一个倒计时效果.最下面有全部源码,需要自取 js语法: setTimeout:定时器 document.getElementById:Document的方法 getElementById()返回一个匹配特定 ID的元素。由于元素的 ID 在大部分情况下要求是独一无二的&#xff0c;这个方法自然而然地成为了一个高效查找特…

Failed to load local image resource/images/1.jpg无法加载本地图片资源

微信小程序开发无法加载本地图片 先放报错图片 绝对路径不行&#xff0c; <image src"../../images/1.jpg" mode"heightFix"></image>使用相对路径就可以了 <image src"../../images/1.jpg" mode"heightFix"><…