循环队列

循环队列是一种线性数据结构,其操作表现基于 FIFO(First In First Out,先进先出)原则并且队尾被连接在队首以形成一个循环。

这种结构克服了普通队列在元素入队和出队时需要移动大量元素的缺点。

在循环队列中,当元素到达队列尾部时,下一个元素会循环回到队列的开头。

基本概念

  • 队列:队列是一种特殊的线性表,只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作。队列中没有元素时,称为空队列。
  • 循环队列:为了充分利用向量空间,克服“假溢出”的现象,将队列存储空间的最后一个位置绕到第一个位置,形成逻辑上的环状空间,供队列循环使用。

循环队列的实现

循环队列通常使用数组来实现,并设置两个指针:front(队首指针)和rear(队尾指针)。它们分别指向队列的第一个元素和最后一个元素的下一个位置。

  • 初始化:设置front = 0rear = -1(或rear = 0,但此时队列为空,所以最好使用-1表示没有元素)。
  • 入队(enqueue)
    • 如果队列已满((rear + 1) % size == front),则无法添加新元素。
    • 否则,将元素添加到rear所指向的位置,并将rear向后移动一位((rear + 1) % size)。
  • 出队(dequeue)
    • 如果队列为空(front == rear),则无法删除元素。
    • 否则,从front所指向的位置删除元素,并将front向后移动一位((front + 1) % size)。
  • 判断队列是否为空front == rear
  • 判断队列是否已满(rear + 1) % size == front(注意这里使用取模运算来处理循环)

示例

假设有一个循环队列的容量为5,初始时front = 0rear = -1。当依次入队元素1, 2, 3, 4, 5后,front = 0rear = 4。如果再入队一个元素6,则rear会变为0(因为(4 + 1) % 5 = 0),此时frontrear再次相等,但队列并没有满,因为它们是循环的。

优点

  • 循环队列克服了假溢出的现象,能够更充分地利用存储空间。
  • 通过取模运算,可以快速定位队首和队尾的位置,实现高效的入队和出队操作。

注意事项

  • 在计算队列长度时,需要使用(rear - front + capacity) % capacity(如果rear < front)或(rear - front + 1)(如果rear >= front)来确保得到正确的长度。
  • frontrear相等时,需要根据队列的初始化情况来判断队列是为空还是满。一种常见的做法是在入队时检查是否已满,在出队时检查是否为空。

让我们看看代码吧~~~

public class Queue {
    private int[] elements;//用于存储队列元素的数组。
    private int size;//当前队列中的元素数量
    private int front; // 指向队列前端(即下一个出队元素)的索引
    private int rear;  // 指向队列后端(即下一个入队位置)的索引
    //构造函数:初始化一个大小为8的数组
    public Queue() {
        elements = new int[8];
        size = 0;//表示队列当前为空
        front = 0;//表示队列的前端在数组的起始位置
        rear = -1;//表示队列的后端还没有放置任何元素(即将要放置的第一个元素会在索引0处)
    }
    public void enqueue(int v) {
        if (size == elements.length) {//检查队列是否已满(即 size 是否等于 elements 的长度)
            //如果队列已满,则创建一个新的、容量是原来两倍的数组
            int[] newElements = new int[elements.length * 2];
            for (int i = 0; i < size; i++) {
                newElements[i] = elements[(front + i) % elements.length];
            }
            elements = newElements;//将elements的引用更新为新创建的数组newElements
            front = 0;
            rear = size - 1;
        }
        rear = (rear + 1) % elements.length;
        elements[rear] = v;
        size++;
    }

    public int dequeue() {
        if (empty()) {//检查队列是否为空(使用empty()方法)。如果队列为空,则抛出一个运行时异常。
            throw new RuntimeException("Queue is empty");
        }
        int v = elements[front];//获取front所指向的元素的值,并将其存储在变量v中
        front = (front + 1) % elements.length;//front指针以指向下一个元素
        size--;
        return v;
    }
//如果size为0,则返回true;否则返回false
    public boolean empty() {
        return size == 0;
    }

    public int getSize() {
        return size;
    }
}

我们把其中关键代码进行详细分析一下:

elements = newElements;//将elements的引用更新为新创建的数组newElements
front = 0;
rear = size - 1;

elements = newElements; 这行代码是一个赋值操作,它将 newElements 数组的引用赋值给 elements 变量。这意味着从现在开始,elements 和 newElements 都指向同一个数组对象在内存中的位置。

这样做有几个重要的影响:

  1. 内存管理:原数组elements(以及它之前指向的内存空间)不再被Queue类的任何成员变量引用。如果没有其他引用指向这个数组,那么它将成为垃圾回收(Garbage Collection)的目标,内存空间会被释放。
  2. 后续操作:之后对elements的任何操作(如添加、删除或访问元素)都会在新数组上进行,而不是在原来的小数组上。
  3. 引用更新:由于frontrear指针是相对于elements数组来计算的,所以在更新elements引用后,你需要相应地更新front的值(在你的例子中,它被设置为0),以确保后续操作正确。rear的值在复制元素后已经是正确的(即size - 1),因为它指向的是新数组中最后一个元素的下一个位置。
rear = (rear + 1) % elements.length;
elements[rear] = v;
size++;

这三行代码是队列实现中用于执行入队(enqueue)操作的关键部分,具体来说:

rear = (rear + 1) % elements.length;

这行代码是在更新队列的尾部(rear)指针。队列是一种先进先出(FIFO)的数据结构,新元素总是添加到队列的尾部。由于队列可能是一个循环队列,因此需要使用模运算(%)来确保rear的值在数组的有效索引范围内。如果rear加1后超出了数组的长度,模运算会将其“回绕”到数组的起始位置。

elements[rear] = v;

这行代码是将新元素v存储在数组的rear位置。这是队列中元素添加的实际操作,它将新元素放置在队列的尾部。

size++;

这行代码是增加队列的大小(size。队列的大小表示队列中当前存储的元素数量。每当一个新元素被添加到队列时,队列的大小就应该增加1。

综上所述,这三行代码共同完成了队列的入队操作:更新尾部指针、在尾部添加新元素、并增加队列的大小。

 

public int dequeue() {
        if (empty()) {//检查队列是否为空(使用empty()方法)。如果队列为空,则抛出一个运行时异常。
            throw new RuntimeException("Queue is empty");
        }
        int v = elements[front];//获取front所指向的元素的值,并将其存储在变量v中
        front = (front + 1) % elements.length;//front指针以指向下一个元素
        size--;
        return v;
    }

 int v = elements[front];

这里,elements 是一个数组(通常用于存储队列中的元素),而 front 是一个变量(通常是一个索引),指向队列中的第一个元素。这行代码从 elements 数组中取出 front 索引处的元素值,并将其存储在变量 v 中。

front = (front + 1) % elements.length;

这行代码更新 front 指针以指向队列中的下一个元素。由于队列可能是循环的(即数组首尾相连),所以使用模运算 % 来确保 front 的值在数组的有效范围内。如果 front 已经指向数组的最后一个元素,则将其重置为数组的起始位置(索引为 0)。

size--

 这行代码减少队列的 size 变量值,以反映队列中元素数量的减少。size 通常是一个变量,用于跟踪队列中当前元素的数量。

今天就先介绍这个了,我们下期见!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Centos实现Mysql8.4安装及主主同步

8.4的Msyql在同步的时候与之前的版本有很大不同&#xff0c;这里记录一下安装流程 Mysql安装 官网下载 选择自己的版本&#xff0c;选第一个 复制下载链接 在服务器上创建一个msyql目录 使用命令下载,链接换自己的 wget https://dev.mysql.com/get/mysql84-community-relea…

跟着刘二大人学pytorch(第---10---节课之卷积神经网络)

文章目录 0 前言0.1 课程链接&#xff1a;0.2 课件下载地址&#xff1a; 回忆卷积卷积过程&#xff08;以输入为单通道、1个卷积核为例&#xff09;卷积过程&#xff08;以输入为3通道、1个卷积核为例&#xff09;卷积过程&#xff08;以输入为N通道、1个卷积核为例&#xff09…

接口测试工作准备

前面已经讲了接口测试的原理&#xff0c;接下来讲接口测试如何准备。分为了解项目背景、收集项目相关资料、部署接口测试环境。 1、了解项目背景 1、首先我们应该去了解项目的应用范围&#xff0c;了解业务场景需要调用的接口&#xff0c;确定接口测试的接口个数、接口名字、接…

Spring配置那些事

一、引言 配置是一个项目中不那么起眼&#xff0c;但却有非常重要的东西。在工程项目中&#xff0c;我们一般会将可修改、易变、不确定的值作为配置项&#xff0c;在配置文件/配置中心中设置。 比方说&#xff0c;不同环境有不同的数据库地址、不同的线程池大小等&#xff0c…

创建STM32F10X空项目教程

创建STM32F10X系列的空项目工程 官网下载STM32标准外设软件库 STM32标准外设软件库 创建一个空文件夹作为主工程文件夹在主工程文件夹中&#xff0c;创建三个空文件夹 CMSIS - 存放内核函数及启动引导文件 FWLIB - 存放库函数 USER - 存放用户的函数将STM32标准外设软件库文件…

Git学习记录v1.0

1、常用操作 git clonegit configgit branchgitt checkoutgit statusgit addgit commitgit pushgit pullgit loggit tag 1.1 git clone 从git服务器拉取代码 git clone https://gitee.com/xxx/studyJava.git1.2 git config 配置开发者用户名和邮箱 git config user.name …

Javaweb04-Servlet技术2(HttpServletResponse, HttpServletRequest)

Servlet技术基础 HttpServletResponse对象 HttpServletResponce对象是继承ServletResponse接口&#xff0c;专门用于封装Http请求 HttpServletResponce有关响应行的方法 方法说明功能描述void setStatus(int stauts)用于设置HTTP响应消息的状态码&#xff0c;并生成响应状态…

【C++ 11 新特性】lambda 表达式详解

文章目录 1. 常见 lambda 面试题&#x1f58a; 1. 常见 lambda 面试题&#x1f58a; &#x1f34e;① 如果⼀个 lambda 表达式作为参数传递给⼀个函数&#xff0c;那这个函数可以使⽤这个 lambda 表达式捕获的变量吗 ? &#x1f427; 函数本身无法直接访问到 lambda表达式捕获…

教资认定报名照片要求小于190kb…

教资认定报名照片要求小于190kb…… 要求&#xff1a;文件小于190kb&#xff0c;宽度290-300&#xff0c;高度408-418 方法&#xff1a;vx搜随时照-教资认定 直接制作合规尺寸即可&#xff0c;还可以打印纸质版邮寄到家

ffmpeg解封装rtsp并录制视频-(2)使用VLC模拟一个rtsp服务器并用ffmpeg解封装该rtsp流

VCL模拟服务器并打开播放该视频文件&#xff1a; - 准备好一个mp4文件&#xff0c;打开vlc软件 - 选择“媒体”》“流” - 添加一个mp4文件 - 点击下方按钮选择“串流” - 下一步目标选择rtsp 点击“添加” - 端口默认8554 - 路径设置 /test - 用…

JavaFX VBox

VBox布局将子节点堆叠在垂直列中。新添加的子节点被放置在上一个子节点的下面。默认情况下&#xff0c;VBox尊重子节点的首选宽度和高度。 当父节点不可调整大小时&#xff0c;例如Group节点&#xff0c;最大垂直列的宽度基于具有最大优选宽度的节点。 默认情况下&#xff0c;…

揭秘神秘的种子:Adobe联合宾夕法尼亚大学发布文本到图像扩散模型大规模种子分析

文章链接&#xff1a;https://arxiv.org/pdf/2405.14828 最近对文本到图像&#xff08;T2I&#xff09;扩散模型的进展促进了创造性和逼真的图像合成。通过变化随机种子&#xff0c;可以为固定的文本提示生成各种图像。在技术上&#xff0c;种子控制着初始噪声&#xff0c;并…

Linux_应用篇(17) FrameBuffer 应用编程

本章学习 Linux 下的 Framebuffer 应用编程&#xff0c; 通过对本章内容的学习&#xff0c; 大家将会了解到 Framebuffer 设备究竟是什么&#xff1f;以及如何编写应用程序来操控 FrameBuffer 设备。 本章将会讨论如下主题。 ⚫ 什么是 Framebuffer 设备&#xff1f; ⚫ LCD 显…

分布式系统中的经典思想实验——两将军问题和拜占庭将军问题

文章目录 一、两将军问题1.1 问题描述1.2 深入理解两将军问题1.3 实验结论 二、拜占庭将军问题2.1 问题描述2.2 深入理解拜占庭将军问题2.3 解决方案 三、两将军和拜占庭问题的关系3.1 区别和联系3.2 应用与现实意义 参考资料 一、两将军问题 1.1 问题描述 两将军问题描述的是…

BetterZip 5软件详细安装步骤(最新版软件下载)

​BetterZip是一款功能强大的Mac解/压缩软件&#xff0c;可以满足用户对文件压缩、解压、加密和保护等方面的需求。以下是关于BetterZip软件的主要功能、特点和使用方法的详细介绍&#xff0c;以及对其用户友好度、稳定性和安全性的评价。 安 装 包 获 取 地 址: BetterZip 5-…

半导体芯片结构以及译码驱动

一.半导体芯片结构 可能并不是只有一个芯片&#xff0c;有多个芯片就需要片选线了。 二.半导体存储芯片的译码驱动 主要有两种方式&#xff1a;线选法和重合法 线选法&#xff1a;每一个存储单元都用一根字选择线选中&#xff0c;直接选中存储单元的各位。&#xff08;一维…

从 Acme.Sh V3.0 说说 ZeroSSL

熟悉明月的都知道&#xff0c;明月一直都在使用 acme.sh 作为服务器端申请、部署、续期免费 SSL 证书的主要工具&#xff0c;今天在帮一个站长申请 SSL 证书的时候发现 acme.sh v3.0 开始默认的免费 SSL 证书变更为&#xff1a;ZeroSSL 了&#xff0c;这个 ZeroSSL 其实跟明月一…

Java NIO ByteBuffer 使用方法

前言 最近在使用spring boot websocket xterm.js 给 k8s pod做了个在线的 web 终端&#xff0c;发现websocket的类核心方法&#xff0c;用的都是ByteBuffer传递数据&#xff0c;如下&#xff1a; OnMessagepublic void onMessage(Session session, ByteBuffer byteBuffer) {…

【深度学习量化交易1】一个金融小白尝试量化交易的设想、畅享和遐想

关注我的朋友们可能知道&#xff0c;我经常在信号处理的领域出没&#xff0c;时不时会发一些信号处理、深度学习科普向的文章。 不过算法研究久了&#xff0c;总想做一些更有趣的事情。 比如用深度学习算法赚大钱。。毕竟有什么事情能比暴富更有意思呢。 一、神经网络与彩票…

Vue - 实现登录页面

1、技术框架 1、技术框架Vue-Cli Vue3.0 2、界面推荐大小&#xff1a; 1920 * 1080 3、UI组件&#xff1a;elementui 4、icon: element-plus/icons-vue 5、node版本&#xff1a;v20.14.0 2、效果图 3、源代码部分截图 4、其他 有需要的请联系作者。需要购买&#xff0c;不白…