循环队列来了解一下!!

news2024/9/24 19:19:14

笔者在之前的一篇文章,详细的介绍了:队列之单向链表与双向链表的模拟实现:https://blog.csdn.net/weixin_64308540/article/details/128742090?spm=1001.2014.3001.5502 感兴趣的各位老铁,可以参考一下啦!

下面进入循环队列的讲解部分:

对于队列,在这个之前我们就已经知道:需要用数组来实现!!数组!

实际中我们有时还会使用一种队列叫循环队列。如操作系统课程讲解生产者消费者模型时可以就会使用循环队列。 环形队列通常使用数组实现。

当我们给其下标的时候:

假设:我们在里面存储数据的时候:

每次存储一个数据,那么rear就往后走一步!当这个情况下:

  1. rear从7下标如何到0下标??(怎么过去?)

  1. 假设rear从7下标已经到0下标,那么此时,到底是满了?还是没满??这也是一个值得思考的问题!!

  1. 需要注意以下的这种情况:

在这种情况下:当我们一边存储,一边删除,那么就会出现,不是在0下标相遇的情况!因此,我们需要注意:这种情况下,如何判断循环列表是否已经存储满了呢??

解决方案:

对于问题1:我们可以用:rear=(rear+1)%length,length表示数组长度!这样就可以实现数组下标的跨越!

对于问题2:我们可以定义usedSize记录存储的有效数据,通过usedSize与数组的长度相比,那么,我们就可以清晰的得出,循环列表是否存储满的结论!

对于如何判断循环列表满的情况:我们可以用牺牲一个空间来表示满!!

在这个思路过程中,我们可以让rear先走一步,看看是否与front相遇,若相遇(上图的情况)则为满!在上图中:我们牺牲rear所对应的空间来表示满!!

经过上述的讲解,那么,我们已经知道了循环列表的操作,及其思路,接下来我们就可以:设计循环队列了!:622. 设计循环队列 - 力扣(LeetCode)

622. 设计循环队列

难度中等440收藏分享切换为英文接收动态反馈

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

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

你的实现应该支持如下操作:

  • MyCircularQueue(k): 构造器,设置队列长度为 k 。

  • Front: 从队首获取元素。如果队列为空,返回 -1 。

  • Rear: 获取队尾元素。如果队列为空,返回 -1 。

  • enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。

  • deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。

  • isEmpty(): 检查循环队列是否为空。

  • isFull(): 检查循环队列是否已满。

示例:

MyCircularQueue circularQueue = new MyCircularQueue(3); // 设置长度为 3
circularQueue.enQueue(1);  // 返回 true
circularQueue.enQueue(2);  // 返回 true
circularQueue.enQueue(3);  // 返回 true
circularQueue.enQueue(4);  // 返回 false,队列已满
circularQueue.Rear();  // 返回 3
circularQueue.isFull();  // 返回 true
circularQueue.deQueue();  // 返回 true
circularQueue.enQueue(4);  // 返回 true
circularQueue.Rear();  // 返回 4

提示:

  • 所有的值都在 0 至 1000 的范围内;

  • 操作数将在 1 至 1000 的范围内;

  • 请不要使用内置的队列库。

经过上述 的题目分析,我们可以写出一下的简单代码:

首先,根据题目中的代码,我们定义了一个:MyCircularQueue的类!

然后我们开始进行代码的准备阶段:

    private int[] elem;//数组
    private int front;//表示列表的头
    private int rear;//表示列表的尾

在之前的分析中,我们知道,循环队列的底层是一个数组,因此,我们第一了一个数组,一个front表示列表的头,rear表示列表的尾!!

根据构造器来定义数组的长度为k,但是,由于我们所用的是:浪费一个空间来表示满的情况:因此我们需要多定义一个数组的长度:k+1

   //构造器,设置队列的长度为k
    public MyCircularQueue(int k){
        //如果是浪费空间,这里必须多加一个!
        this.elem=new int[k+1];
    }
  1. 入队列:向循环列表中插入一个元素,如果插入成功则返回true

    //入队列:向循环列表中插入一个元素,如果插入成功则返回true
    public boolean enQueue(int value){
        //检查队列是否为满??
        if (isFull()){
            return false;//在不扩容的情况下,满了,就不能入!
        }
        //在队列不满的情况下
        elem[rear]=value;//存放数据
        rear=(rear+1)%elem.length;//确保循环
        return true;
    }

在这个里面,我们用了一个检查队列是否为满的判断,所以:……

 //检查循环队列是否为满?
    public boolean isFull(){
        //第一种写法
        if ((rear+1)%elem.length==front){
            return true;
        }
        return false;

        //第二种写法:
        //return (rear+1)%elem.length==front;
    }

其实这个第二种的写法,很简单!很简单!

  1. 从循环队列中删除一个元素,如果成功删除,则返回true

  //从循环队列中删除一个元素,如果成功删除,则返回true
    public boolean deQueue(){
        if (isFull()){
            return false;
        }
        front=(front+1)% elem.length;
        return true;
    }
    

对于上述的这个代码,通过front往后走了一步,此时数据还在循环队列里面,但是,由于没有记录下来,所以,便就相当于删除了!

  1. 从队列的队首获取元素,如果队列为空,则返回-1

   //从队列的队首获取元素,如果队列为空,则返回-1
    public int Front(){
        if (isFull()) {
            return -1;
        }
        //得到对头元素
        return elem[front];
    }

这个代码很简单,笔者就不再详细的介绍了!

  1. 获取队列的队尾元素,如果队列为空,则返回-1

    //获取队列的队尾元素,如果队列为空,则返回-1
    public int Rear(){
        if (isEmpty()){
            return -1;
        }
        //得到队尾元素
        int index=(rear==0)?elem.length-1 :rear-1;
        return elem[index];
    }
    

对于这个问题,我们需要思考的是:rear在0下标的时候,若直接返回elem[rear-1],可能会造成越界!!因此我们才有着上述的: int index=(rear==0)?elem.length-1 :rear-1; return elem[index];

在上述的过程中,我们使用了检查数组是否为空的情况:isEmpty()

 //检查数组是否为空
    public boolean isEmpty(){
        return front==rear;//相遇
    }

上述便是我们的全部思路,因此,我们的整体代码为:

public class MyCircularQueue {
    private int[] elem;//数组
    private int front;//表示列表的头
    private int rear;//表示列表的尾

    //构造器,设置队列的长度为k
    public MyCircularQueue(int k) {
        //如果是浪费空间,这里必须多加一个!
        this.elem = new int[k + 1];
    }

    //入队列:向循环列表中插入一个元素,如果插入成功则返回true
    public boolean enQueue(int value) {
        //检查队列是否为满??
        if (isFull()) {
            return false;//在不扩容的情况下,满了,就不能入!
        }
        //在队列不满的情况下
        elem[rear] = value;
        rear = (rear + 1) % elem.length;
        return true;
    }

    //检查循环队列是否为满?
    public boolean isFull() {
        //第一种写法
        if ((rear + 1) % elem.length == front) {
            return true;
        }
        return false;

        //第二种写法:
        //return (rear+1)%elem.length==front;
    }

    //从循环队列中删除一个元素,如果成功删除,则返回true
    public boolean deQueue(){
        if (isFull()){
            return false;
        }
        front=(front+1)% elem.length;
        return true;
    }

    //从队列的队首获取元素,如果队列为空,则返回-1
    public int Front(){
        if (isFull()) {
            return -1;
        }
        //得到对头元素
        return elem[front];
    }

    //获取队列的队尾元素,如果队列为空,则返回-1
    public int Rear(){
        if (isEmpty()){
            return -1;
        }
        //得到队尾元素
        int index=(rear==0)?elem.length-1 :rear-1;
        return elem[index];
    }

    //检查数组是否为空
    public boolean isEmpty(){
        return front==rear;//相遇
    }
}

若有不懂得地方,可以私聊我一下!!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于Java+SpringBoot+Vue前后端分离酒店管理系统设计与实现

博主介绍:✌全网粉丝3W,全栈开发工程师,从事多年软件开发,在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建、毕业项目实战、项目定制✌ 博主作品:《微服务实战》专栏是本人的实战经验总结,《S…

linux系统常用命令

目录 一、系统介绍 二、Linux常用命令 1、Linux命令格式 2、文件目录操作命令:ls 3、文件目录操作命令:cd 4、文件目录操作命令:cat 5、文件目录操作命令:more 6、文件目录操作命令:tail 7、创建文件命令&…

【三维点云】01-激光雷达原理与应用

文章目录内容概要1 激光雷达原理1.1 什么是激光雷达?1.2 激光雷达原理1.3 激光雷达分类三角法TOF法脉冲间隔测量法幅度调制的相位测量法相干法激光雷达用途2 激光雷达安装、标定与同步2.1 激光雷达安装方式考虑因素2.2 激光雷达点云用途2.3 数据融合多激光雷达数据融…

Rust学习入门--【7】Rust 数据类型

类型系统 对于任何一门语言都是重中之重,因为它体现了语言所支持的不同类型的值。 类型系统 也是 IT 初学者最难啃的三座大山之一,而类型系统之所以难以理解,主要是没有合适的现成的参考体系。 我们说类型系统 存在的目的,就是 …

【代码随想录】-动态规划专题

文章目录理论基础斐波拉契数列爬楼梯使用最小花费爬楼梯不同路径不同路径 II整数拆分不同的二叉搜索树背包问题——理论基础01背包二维dp数组01背包一维数组(滚动数组)装满背包分割等和子集最后一块石头的重量 II目标和一和零完全背包零钱兑换 II组合总和…

JVM学习03:垃圾回收

JVM学习03:垃圾回收 1、如何判断对象可以回收 1.1、引用计数法 记录当前对象被引用的次数,当引用次数为0时则进行垃圾回收。缺点:当两个对象互相引用但并没有其他对象再引用它们时,他们的引用次数都为1,无法对其进行…

Spring Security in Action 第三章 SpringSecurity管理用户

本专栏将从基础开始,循序渐进,以实战为线索,逐步深入SpringSecurity相关知识相关知识,打造完整的SpringSecurity学习步骤,提升工程化编码能力和思维能力,写出高质量代码。希望大家都能够从中有所收获&#…

牛客寒假集训营6 E 阿宁的生成树

E-阿宁的生成树_2023牛客寒假算法基础集训营6 (nowcoder.com)开始慢慢补牛牛的题题意&#xff1a;最小生成树质数距离思路&#xff1a;最小生成树一共就两种算法&#xff0c;我们考虑Prim的过程初始连通块是1&#xff0c;然后考虑拿1和其他的结点连边当j-i<k时边权是gcd&…

【JavaSE】方法的使用

方法的使用BIT-5-方法的使用绪论1. 方法概念及使用1.1什么是方法1.2 方法定义1.3 实参和形参的关系&#xff08;重要&#xff09;1.4 没有返回值的方法2. 方法重载2.1 为什么需要方法重载2.2 方法重载概念3. 递归3.1 生活中的故事3.2 递归的概念3.2 递归执行过程分析3.3 递归练…

C++之异常处理

异常异常是面向对象语言处理错误的一种方式。当一个函数出现自己无法处理的错误时&#xff0c;可以抛出异常&#xff0c;然后输的直接或者间接调用者处理这个错误。语法捕获全部的异常try {//可能抛出异常的代码//throw异常对象 } catch(...) {//不管什么异常&#xff0c;都在这…

Java之动态规划之子序列问题

目录 0.动态规划问题 一.最长递增子序列 1.题目描述 2.问题分析 3.代码实现 二.最长递增子序列 1.题目描述 2.问题分析 3.代码实现 三.最长重复子数组 1.题目描述 2.问题分析 3.代码实现 4.代码的优化(滚动数组) 四.最长公共子序列 1.题目描述 2.问题分析 3.代…

C语言学习笔记(五):数组的使用

数组的定义 数组是一组有序数据的集合。数组中各数据的排列是有一定规律的&#xff0c;下标代表数据在数组中的序号。 用数组名和下标即可唯一地确定数组中的元素。 数组中的每一个元素都属于同一个数据类型。 一维数组 定义与引用 int a[10] {0,1,2,3,4,5,6,7,8&#xf…

Matlab绘制隐函数总结-二维和三维

1.二维隐函数 二维隐函数满足f(x,y)0f(x,y)0f(x,y)0&#xff0c;这里无法得到yf(x)yf(x)yf(x)的形式。不能通过普通函数绘制。 我们要关注的是使用fplot函数和fimplicit函数。 第1种情况&#xff1a;基本隐函数 基本的隐函数形式形如&#xff1a; x2y22x2(x2y2)12x^{2}y^{…

【Qt】Qt 隐式共享

文章目录一、导读二、隐式共享简介三、源码角度分析隐式共享四、隐式共享在开发中的使用五、隐式共享迭代器问题六、隐式共享类和线程一、导读 在实际开发中&#xff0c;Qt中很多类可以直接作为函数参数传递&#xff0c;这样做是为了什么&#xff1f;其背后的实现机制又是什么…

进程,线程

进程是操作系统分配资源的基本单位&#xff0c;线程是CPU调度的基本单位。 PCB&#xff1a;进程控制块&#xff0c;操作系统描述程序的运行状态&#xff0c;通过结构体task,struct{…}&#xff0c;统称为PCB&#xff08;process control block&#xff09;。是进程管理和控制的…

#电子电气架构——Vector工具常见问题解决三板斧

我是穿拖鞋的汉子,魔都中一位坚持长期主义的工科男。 今天在与母亲聊天时,得到老家隔壁邻居一位大姐年初去世的消息,挺让自己感到伤感!岁月如流水,想抓都抓不住。想起平时自己加班的那个程度,可能后续也要自己注意身体啦。 老规矩,分享一段喜欢的文字,避免自己成为高知…

千锋教育嵌入式物联网教程之系统编程篇学习-03

目录 进程的终止 exit函数 _exit函数 进程退出清理 进程间的替换 进程间通信 常见通信机制 进程间通信的实质 信号 产生信号的方式 信号的默认处理方式 进程对信号的处理方式 kill函数 进程的终止 使用exit函数对进程进行终止&#xff0c;而return只是结束函数&a…

电子技术——共模抑制

电子技术——共模抑制 我们在之前学习过&#xff0c;无论是MOS还是BJT的差分输入对&#xff0c;共模信号并不会改变漏极电流的大小&#xff0c;因此我们说差分输入对共模信号无响应。但是实际上由于各种客观非理想因素&#xff0c;例如电流源有限阻抗等&#xff0c;此时共模是影…

LINUX提权入门手册

前言 发点存货 LINUX权限简介 在学习提权之前我们先了解一下linux里面的权限我们使用命令: ls -al即可查看列出文件所属的权限&#xff1a; 文件头前面都有一段类似的字符&#xff0c;下面我们仔细分析一下里面符号分别代表什么。 -rw-r--r-- 1 root root 第一个符号-的…

现代 cmake (cmake 3.x) 操作大全

cmake 是一个跨平台编译工具&#xff0c;它面向各种平台提供适配的编译系统配置文件&#xff0c;进而调用这些编译系统完成编译工作。cmake 进入3.x 版本&#xff0c;指令大量更新&#xff0c;一些老的指令开始被新的指令集替代&#xff0c;并加入了一些更加高效的指令/参数。本…