日撸Java三百行(day18:循环队列)
目录
一、顺序队列与循环队列
二、代码实现
1.循环队列创建
2.循环队列遍历
3.循环队列入队
4.循环队列出队
5.数据测试
6.完整的程序代码
总结
一、顺序队列与循环队列
在昨天,我们提到队列实现除了采用链式存储结构,还可以采用顺序存储结构(因为队列是线性表,所以和线性表一样也有顺序、链式两种存储结构)。采用顺序存储结构的队列叫做顺序队列,它是用一组地址连续的存储单元依次存放从队头到队尾的队列元素,其中,需要附设头指针head和尾指针tail,分别指向队头元素和队尾元素。
为方便理解,下面我们用图示进行相关说明(假设队列的总存储空间TOTAL_SPACE = 5):
可以预测,如果我们在元素E之后再插入元素F,那么必然会插入失败,这是因为此时的尾指针tail已经达到队列的最大长度5,所以没办法继续插入元素。但事实上我们可以看到,此时下标为0的存储单元其实是空的,也就是说实际上此时的队列并没有满,这种现象就叫做“假溢出”。
简单来说,“假溢出”的原因就是队列在队头出队、队尾入队,从而造成队头出现空闲单元未被充分利用。为了解决这种“假溢出”现象,避免存储空间浪费,我们将队列的数组看作是头尾相接的循环结构,这种队列头尾相接的循环顺序存储结构就是循环队列,通过这种方式可以重用队头空闲下来的存储单元,如下图:
在循环队列中进行入队、出队操作,头尾指针的指向仍然要+1,不过不同的是,当头尾指针指向TOTAL_SPACE - 1(即头尾指针到达队列的最大长度处)时,此时再+1的结果就变成了头尾指针指向队列下标为0的地方。这种循环意义下的+1操作,可以用以下两种方式进行实现:
-
if( i == TOTAL_SPACE - 1) // i表示head或taili = 0; elsei++;
-
i = (i+1) % TOTAL_SPACE; // i表示head或者tail
对于第二种方式,很明显,当头尾指针指向TOTAL_SPACE - 1(即 i = TOTAL_SPACE - 1)时,i + 1就等于TOTAL_SPACE,进行整除运算后得到余数为0,所以i最后等于0;其余时候,i + 1均小于TOTAL_SPACE,所以整除后得到的余数即为i + 1本身,即i最后就等于i + 1。
通过上图,我们还可以发现,当循环队列为空或者已满时,头指针head均等于尾指针tail,这就会导致一个问题:当head = tail时,到底是判空还是判满?
可以通过以下三种方法来解决这个问题(在今天的代码实现中,我们用的是第二种方法):
- 另外设置一个布尔变量,用于区别队空和队满。
- 减少一个存储空间的使用,即把TOTAL_SPACE - 1个队列元素视为已满(也就是说,当下标为TOTAL_SPACE - 2的存储空间被占用,尾指针tail指向TOTAL_SPACE - 1时,视为已满),从而将队空和队满区别开来。因此,队空表示为 head = tail,队满表示为(tail + 1)% TOTAL_SPACE = head。
- 设置一个计数器,用于记录当前队列中的元素个数。计数器初始值为0,新元素入队则计数器+1,元素出队则计数器-1,当计数器 = TOTAL_SPACE时,队满;当计数器 = 0时,队空。
二、代码实现
1.循环队列创建
首先,需要创建类,并定义成员变量、成员方法。由于循环队列是基于顺序表,所以这里大体上和顺序表的创建差不多,只需要再增加头指针head、尾指针tail的声明即可,如下:
public class CircleIntQueue {/*** The total space. One space can never be used.*/public static final int TOTAL_SPACE = 10;/*** The data.*/int[] data;/*** The index for calculating the head. The actual head is head % TOTAL_SPACE.*/int head;/*** The index for calculating the tail.*/int tail;/********************* * The constructor******************* */public CircleIntQueue() {data = new int[TOTAL_SPACE];head = 0;tail = 0;} // Of the first constructor
2.循环队列遍历
/************************ Overrides the method claimed in Object, the superclass of any class.**********************/public String toString() {String resultString = "";if (head == tail) {return "empty";} // Of iffor (int i = head; i < tail; i++) {resultString += data[i % TOTAL_SPACE] + ", ";} // Of for ireturn resultString;} // Of toString
循环队列的遍历没什么好说的,也是通过重写toString()方法,基本上与之前顺序表的遍历一样。
3.循环队列入队
/************************ Enqueue.* * @param paraValue The value of the new node.**********************/public void enqueue(int paraValue) {if ((tail + 1) % TOTAL_SPACE == head) {System.out.println("Queue full.");return;} // Of ifdata[tail % TOTAL_SPACE] = paraValue;tail++;} // Of enqueue
由于顺序表的存储空间有上限,所以在入队之前需要先判断是否队满。根据之前的分析,得到队满判断条件为(tail + 1) % TOTAL_SPACE == head;确定队列未满后,进行入队操作,显然此时tail小于TOTAL_SPACE,所以tail % TOTAL_SPACE = tail,data[ tail % TOTAL_SPACE ]就是指已有队列元素后面第一个空的存储单元,将新元素赋给其即可完成入队,最后不要忘了更新尾指针。
4.循环队列出队
/************************ Dequeue.* * @return The value at the head.**********************/public int dequeue() {if (head == tail) {System.out.println("No element in the queue");return -1;} // Of ifint resultValue = data[head % TOTAL_SPACE];head++;return resultValue;} // Of dequeue
出队只需判断是否队空,而队空的判断条件也十分简单,即head == tail;判断之后,开始出队,因为head小于TOTAL_SPACE,所以head % TOTAL_SPACE = head,data[ head % TOTAL_SPACE ]即为头指针指向的元素,也就是队头的第一个元素;最后,更新头指针,并返回删除的队列元素。
5.数据测试
方法创建完毕后,进行如下的数据测试:
/************************ The entrance of the program.* * @param args Not used now.**********************/public static void main(String args[]) {CircleIntQueue tempQueue = new CircleIntQueue();System.out.println("Initialized, the list is: " + tempQueue.toString());for (int i = 0; i < 5; i++) {tempQueue.enqueue(i + 1);} // Of for iSystem.out.println("Enqueue, the queue is: " + tempQueue.toString());int tempValue = tempQueue.dequeue();System.out.println("Dequeue " + tempValue + ", the queue is: " + tempQueue.toString());for (int i = 0; i < 6; i++) {tempQueue.enqueue(i + 10);System.out.println("Enqueue, the queue is: " + tempQueue.toString());} // Of for ifor (int i = 0; i < 3; i++) {tempValue = tempQueue.dequeue();System.out.println("Dequeue " + tempValue + ", the queue is: " + tempQueue.toString());} // Of for ifor (int i = 0; i < 6; i++) {tempQueue.enqueue(i + 100);System.out.println("Enqueue, the queue is: " + tempQueue.toString());} // Of for i} // Of main
6.完整的程序代码
package datastructure;/*** Circle int queue.**@auther Xin Lin 3101540094@qq.com.*/
public class CircleIntQueue {/*** The total space. One space can never be used.*/public static final int TOTAL_SPACE = 10;/*** The data.*/int[] data;/*** The index for calculating the head. The actual head is head % TOTAL_SPACE.*/int head;/*** The index for calculating the tail.*/int tail;/********************* * The constructor******************* */public CircleIntQueue() {data = new int[TOTAL_SPACE];head = 0;tail = 0;} // Of the first constructor/************************ Enqueue.* * @param paraValue The value of the new node.**********************/public void enqueue(int paraValue) {if ((tail + 1) % TOTAL_SPACE == head) {System.out.println("Queue full.");return;} // Of ifdata[tail % TOTAL_SPACE] = paraValue;tail++;} // Of enqueue/************************ Dequeue.* * @return The value at the head.**********************/public int dequeue() {if (head == tail) {System.out.println("No element in the queue");return -1;} // Of ifint resultValue = data[head % TOTAL_SPACE];head++;return resultValue;} // Of dequeue/************************ Overrides the method claimed in Object, the superclass of any class.**********************/public String toString() {String resultString = "";if (head == tail) {return "empty";} // Of iffor (int i = head; i < tail; i++) {resultString += data[i % TOTAL_SPACE] + ", ";} // Of for ireturn resultString;} // Of toString/************************ The entrance of the program.* * @param args Not used now.**********************/public static void main(String args[]) {CircleIntQueue tempQueue = new CircleIntQueue();System.out.println("Initialized, the list is: " + tempQueue.toString());for (int i = 0; i < 5; i++) {tempQueue.enqueue(i + 1);} // Of for iSystem.out.println("Enqueue, the queue is: " + tempQueue.toString());int tempValue = tempQueue.dequeue();System.out.println("Dequeue " + tempValue + ", the queue is: " + tempQueue.toString());for (int i = 0; i < 6; i++) {tempQueue.enqueue(i + 10);System.out.println("Enqueue, the queue is: " + tempQueue.toString());} // Of for ifor (int i = 0; i < 3; i++) {tempValue = tempQueue.dequeue();System.out.println("Dequeue " + tempValue + ", the queue is: " + tempQueue.toString());} // Of for ifor (int i = 0; i < 6; i++) {tempQueue.enqueue(i + 100);System.out.println("Enqueue, the queue is: " + tempQueue.toString());} // Of for i} // Of main} // Of class CircleIntQueue
运行结果
总结
循环队列是一种特殊类型的队列,它在传统顺序队列的基础上进行优化,通过“环形结构”充分利用存储空间,避免了空间浪费;虽然相比于链队列,循环队列似乎没有那么方便,不过在固定大小的缓冲区和任务调度等需要高效处理的数据流场景,循环队列还是非常适用的。昨天,我们学习了链队列,今天学习了循环队列,二者都是对于队列实现的模拟,这启示我们对于同一种逻辑结构,有时是可以采用不同的物理存储结构来实现的。
相关文章:

日撸Java三百行(day18:循环队列)
目录 一、顺序队列与循环队列 二、代码实现 1.循环队列创建 2.循环队列遍历 3.循环队列入队 4.循环队列出队 5.数据测试 6.完整的程序代码 总结 一、顺序队列与循环队列 在昨天,我们提到队列实现除了采用链式存储结构,还可以采用顺序存储结构&…...

论文精读1
Equivariant Pretrained Transformer for Unified Geometric Learning on Multi-Domain 3D Molecules 核心公式: 论文导图 创新在统一分子建模和块级去噪预训练。...

uniapp免费申请苹果证书教程每次7天可用于测试
准备一个苹果账号没有加入过任何组织的 然后下载appuploader下载链接 登录上去切记勾选上未付苹果688 然后点击苹果证书创建p12证书 创建描述文件 uniapp打包自定义基座 这就打包好了可以愉快地开发了,但每次生成只有7天,设备限制3个,…...

【优秀python大屏】基于python flask的广州历史天气数据应用与可视化大屏
摘要 气象数据分析在各行各业中扮演着重要的角色,尤其对于农业、航空、海洋、军事、资源环境等领域。在这些领域中,准确的气象数据可以对预测未来的自然环境变化和采取行动来减轻负面影响的决策起到至关重要的作用。 本系统基于Python Flask框架&#…...
eBPF编程指南(一):eBPF初体验
1 什么是EBPF? EBPF是一种可以让程序员在内核态执行自己的程序的机制,但是,为了安全起见,无法像内核模块一样随意调用内核的函数,只能调用一些bpf提前定义好的函数。为了让内核执行程序员自己的代码,需要指…...
pip笔记
pip介绍 pip的全称:package installer for python,也就是Python包管理工具。 配置镜像源 镜像列表 阿里云 http://mirrors.aliyun.com/pypi/simple/中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple/豆瓣 http://pypi.douban.com/simple/清华大…...
centos安装postgresql-12
安装pg文件 sudo curl -o /etc/yum.repos.d/pgdg-redhat-all.repo https://mirrors.aliyun.com/postgresql/repos/yum/12/redhat/rhel-7-x86_64/pgdg-redhat-all.repo 清楚缓存重新安装 sudo yum clean all sudo yum makecache 如果报错 删除现有的文件 sudo rm /etc/yum.r…...
Npm使用教程
Npm使用教程 Npm(Node Package Manager)是Node.js的包管理工具和软件包管理系统,广泛用于JavaScript项目的依赖管理和包发布。本文将为你提供一份详细的Npm使用教程,从安装、基本命令、包管理到高级用法,帮助你全面掌…...

【Android Studio】修改项目名称can‘t rename root module解决办法
文章目录 问题现象解决办法 问题现象 修改项目名称 但是直接rename 又会出现 can‘t rename root module 的警告 下图方式只适合修改除项目级别以外的,直接修改项目名称则会报错 解决办法 此时我们只要两步就可以成功修改项目名称了 关闭项目修改其文件夹名称…...

豆瓣Top250电影数据分析可视化系统(Flask+Mysql+Pyecharts)
爬取目标网址:豆瓣Top250 可以看到进入每条电影的详细链接后,显示的内容会更加详细一点 因此我们需要先利用爬虫技术从主页爬取到每条电影的链接,再分别遍历每条电影的链接,获取它的详细内容,这里仅展示一部分代码 利…...

软件质量保证计划书(2024Word完整版)
软件质量保证计划书要点:确立质量目标,组建质保团队,规划全程质控活动,设定质量标准,明确各阶段检查与评审流程,确保各角色职责清晰。强化过程监控,注重数据度量,旨在通过持续改进&a…...

【学习笔记】Matlab和python双语言的学习(动态规划)
文章目录 前言一、动态规划动态规划的基本步骤示例1示例2 三、代码实现----Matlab1.示例12.示例2 四、代码实现----python1.示例12.示例2 总结 前言 通过模型算法,熟练对Matlab和python的应用。 学习视频链接: https://www.bilibili.com/video/BV1EK411…...
低代码开发:机遇与挑战的双重探索
随着科技的迅速发展,“低代码”开发平台悄然兴起,为非专业程序员提供了构建应用程序的快捷途径。无疑,这一创新技术正在颠覆传统的软件开发模式,并激发了IT行业的热烈讨论。但究竟低代码平台是提高开发效率的有利工具,…...

Docker最佳实践(三):安装mysql
大家好,欢迎各位工友。 本篇呢我们就来演示一下如何在Docker中部署MySQL容器,可以按照以下步骤进行: 1. 搜索镜像 首先搜索MySQL镜像,可以使用以下命令: docker search mysql2. 拉取镜像 根据需求选择MySQL或Maria…...

进阶SpringBoot之 Web 静态资源导入
idea 创建一个 web 项目 新建 controller 包下 Java 类,用来查验地址是否能成功运行 package com.demo.web.controller;import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController;RestControl…...

【数据结构七夕专属版】单链表及单链表的实现【附源码和源码讲解】
本篇是博主在学习数据结构时的心得,希望能够帮助到大家,也许有些许遗漏,但博主已经尽了最大努力打破信息差,如果有遗漏还请见谅,嘻嘻,前路漫漫,我们一起前进!!࿰…...

鸿蒙笔记--Socket
这一节主要了解鸿蒙Socket通信,在鸿蒙系统中,Socket TCP通讯是一种常用的网络通信方式,它提供了可靠的、面向连接的数据传输服务。它主要用到ohos.net.socket这个库; constructTCPSocketInstance:创建一个 TCPSocket;…...

安装python+python的基础语法
安装python python2为内置,安装python3----3.6.8 最新安装3.12使用源码安装 1.查看yum源,epel [rootpython01 ~]# yum list installed |grep epel 2.安装python3 [rootpython01 ~]# yum -y install python3 3.查看版本 [rootpython01 ~]# python…...

html+css网页制作 国家体育总局2个页面模版(无js)
htmlcss网页制作 国家体育总局2个页面模版(无js) 网页作品代码简单,可使用任意HTML编辑软件(如:Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作&a…...

Effective Java学习笔记第27、28条原生态类型和非受检警告
目录 什么是泛型 泛型与编译器 不要轻易使用原生态类型 可以通过通配符类型来替代原生态类型 几个适合原生态类型的场景 消除非受检的警告 什么是非受检警告 如果无法消除警告 本书27-33条主要介绍泛型。首先介绍什么是泛型,它的应用场景是什么。然后重点介…...

CMS内容管理系统的设计与实现:多站点模式的实现
在一套内容管理系统中,其实有很多站点,比如企业门户网站,产品手册,知识帮助手册等,因此会需要多个站点,甚至PC、mobile、ipad各有一个站点。 每个站点关联的有站点所在目录及所属的域名。 一、站点表设计…...

CVE-2023-25194源码分析与漏洞复现(Kafka JNDI注入)
漏洞概述 漏洞名称:Apache Kafka Connect JNDI注入导致的远程代码执行漏洞 CVE编号:CVE-2023-25194 CVSS评分:8.8 影响版本:Apache Kafka 2.3.0 - 3.3.2 修复版本:≥ 3.4.0 漏洞类型:反序列化导致的远程代…...
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__ is not explicitly defined.
这个警告表明您在使用Vue的esm-bundler构建版本时,未明确定义编译时特性标志。以下是详细解释和解决方案: 问题原因: 该标志是Vue 3.4引入的编译时特性标志,用于控制生产环境下SSR水合不匹配错误的详细报告1使用esm-bundler…...
基于 HTTP 的单向流式通信协议SSE详解
SSE(Server-Sent Events)详解 🧠 什么是 SSE? SSE(Server-Sent Events) 是 HTML5 标准中定义的一种通信机制,它允许服务器主动将事件推送给客户端(浏览器)。与传统的 H…...

【Qt】控件 QWidget
控件 QWidget 一. 控件概述二. QWidget 的核心属性可用状态:enabled几何:geometrywindows frame 窗口框架的影响 窗口标题:windowTitle窗口图标:windowIconqrc 机制 窗口不透明度:windowOpacity光标:cursor…...
第21节 Node.js 多进程
Node.js本身是以单线程的模式运行的,但它使用的是事件驱动来处理并发,这样有助于我们在多核 cpu 的系统上创建多个子进程,从而提高性能。 每个子进程总是带有三个流对象:child.stdin, child.stdout和child.stderr。他们可能会共享…...

Python[数据结构及算法 --- 栈]
一.栈的概念 在 Python 中,栈(Stack)是一种 “ 后进先出(LIFO)”的数据结构,仅允许在栈顶进行插入(push)和删除(pop)操作。 二.栈的抽象数据类型 1.抽象数…...

【Redis】Redis 的持久化策略
目录 一、RDB 定期备份 1.2 触发方式 1.2.1 手动触发 1.2.2.1 自动触发 RDB 持久化机制的场景 1.2.2.2 检查是否触发 1.2.2.3 线上运维配置 1.3 检索工具 1.4 RDB 备份实现原理 1.5 禁用 RDB 快照 1.6 RDB 优缺点分析 二、AOF 实时备份 2.1 配置文件解析 2.2 开启…...
Fetch API 使用详解:Bearer Token 与 localStorage 实践
Fetch API:现代浏览器内置的用于发送 HTTP 请求的 API,Bearer Token:一种基于令牌的身份验证方案,常用于 JWT 认证,localStorage:浏览器提供的持久化存储方案,用于在客户端存储数据。 token是我…...
【HarmonyOS 5】游戏开发教程
一、开发环境搭建 工具配置 安装DevEco Studio 5.1,启用CodeGenie AI助手(Settings → Tools → AI Assistant)配置游戏模板:选择"Game"类型项目,勾选手机/平板/折叠屏多设备支持 二、游戏引擎核心架构…...