当前位置: 首页 > news >正文

Leetcode:622. 设计循环队列 题解【具详细】

目录

一、题目:

二、思路详解:

1.循环队列的存储定义

2.循环队列的创建

3.循环队列的判空与判断情况

(1) 循环队列的判空:

 (2) 循环队列的判满

4.循环队列元素的插入

5.循环队列元素的删除

6.获取队头元素

7.获取队尾元素 

8.循环队列释放

三、完整代码展示:


一、题目:

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

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

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

  • MyCircularQueue(k): 构造器,设置队列长度为 k 。
  • Front: 从队首获取元素。如果队列为空,返回 -1 。
  • Rear: 获取队尾元素。如果队列为空,返回 -1 。
  • enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
  • deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
  • isEmpty(): 检查循环队列是否为空。
  • isFull(): 检查循环队列是否已满。

难度:中等

题目链接:622. 设计循环队列

示例:

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

题目解析:就是根据题中给的接口进行函数的实现。要求我们实现一个循环队列。

用心阅读下方会有很大的收获。 

二、思路详解:

1.循环队列的存储定义

首先我们需要定义出一个循环队列的存储定义,这里采用的是使用动态数组来进行模拟循环队列,根据题中给出的接口返回类型,我们可以知道循环队列的数据类型为int 。

其次,还需定义两个记录数组的下标,一个记录队列的队头,另一个记录队列的队尾(也就是指向要入队的下一个元素的位置)。另外还要提供一个表示要存储数据的具体个数。

如图:

代码:

//采用动态数组的形式来模拟循环队列
typedef struct {int* a;     //指向数组int front;  //队头int tail;   //队尾int k;      //数据个数
} MyCircularQueue;

2.循环队列的创建

循环队列的创建,先使用malloc进行创建一个 循环队列空间

接着根据给的数据个数k让指针a指向一个动态数组,在分别对front,tail,k进行初始化,注意tail = 0表示要存放的下一个数据元素的位置,对动态数组a开辟空间的时候要多开辟一个空间,避免假溢出的现象。最后一定要返回之前创建的循环队列。

代码:

//创建长度为k的循环队列
MyCircularQueue* myCircularQueueCreate(int k) {//使用动态内存函数来申请内存//这里多申请一个空间的目的是防止假溢出//使用malloc创建一个循环队列MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));//为循环队列里面的指针a ,让a指向一个长度为k+1的数组obj->a= (int*)malloc(sizeof(int)*(k+1));obj->front = 0; //队头从数组的下标0开始obj->tail = 0; //队尾指向下一个元素obj->k = k; //队列的长度为kreturn obj;
}

物理存储情况,如图:

但是我们一般会到其循环的逻辑结构,逻辑存储,如图:

 3.循环队列的判空与判断情况

循环队列的插入和删除是不可避免的,当这之前就需要先完成判和判满的接口。注意:一定要把判空和判满的函数实现放在队列插入和删除函数实现的前面。

(1) 循环队列的判空:

根据函数的返回类型是bool,空我们就返回true ,否则返回false。

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

因为这里采取的是通过动态数组来模拟循环队列,所以队列空的条件就是当front == tail 的时候,此时的循环队列就是空的。

如图:

代码:

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {//队空,就是队头与队尾相同时return obj->front == obj->tail;
}
 (2) 循环队列的判满

 同样根据函数的返回类型是bool,空我们就返回true ,否则返回false。

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

什么时候会满呢?当(tail+1)%(k+1) == front,就是队尾下标加1模开辟空间的个数 

可能很多会对为什么要多开辟一个空间,原因就在这:对于队列的判满的情况,

当没有创建的额外空间,队列只有数据10 和 11 的情况下,

像上图就是假溢出现象,这个队列并没有满。

总的来说:

循环队列为了区分队列的空和满,需要额外增加一个空的元素来占据队列的一个位置,这样队列满的状态就可以通过头尾指针相邻且不重合来判断,而不会出现头尾指针重合但队列实际上并不满的情况。同时循环队列需要对头尾指针进行模运算,如果没有额外的空间,那么当队列最后一个元素占据了数组最后一个位置时,下一个元素就会从数组的第一个位置开始,这样就无法正确进行模运算,而增加一个空的元素可以解决这个问题。

 代码:

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

 4.循环队列元素的插入

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

插入前判断是否满,满就返回false,接着就是数据的插入,插入后,对tail下标进行取模(因为是反复利用原来的空间,还有就是避免溢出),插入成功就返回true。

 代码:

//插入元素
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {//插入元素前先进行判断是否满if(myCircularQueueIsFull(obj)){return false;}//插入元素使用尾插obj->a[obj->tail] = value;obj->tail++;//避免tail的下标越界obj->tail%=(obj->k+1);return true;
}

5.循环队列元素的删除

 删除前,要进行判断是否为空。队头减一,进行删除,删除后取模。

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

 代码:

//出队
bool myCircularQueueDeQueue(MyCircularQueue* obj) {//删除元素队列不能为空if(myCircularQueueIsEmpty(obj)){return false;}//出队,头删obj->front++;obj->front%=(obj->k+1);return true;
}

 6.获取队头元素

获取前进行判断,是否为空。

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

  代码:

//获取队首元素
int myCircularQueueFront(MyCircularQueue* obj) {//队列不能为空if(myCircularQueueIsEmpty(obj)){return -1; //队空返回-1}return obj->a[obj->front];
}

7.获取队尾元素 

获取前进行判断,是否为空。

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

  代码:

//获取队尾元素
int myCircularQueueRear(MyCircularQueue* obj) {//队列不能为空if(myCircularQueueIsEmpty(obj)){return -1; //队空返回-1}//注意当tail = 0的情况return obj->a[(obj->tail - 1+ obj->k+1)%(obj->k+1)];
}

解释一下 上述最后一行代码:

重点:

首先tail是指向要存放下一个元素的位置,找队尾元素时,tail要进行-1。

 因为数组下标最小是从0开始的,当tail ==0且队列不为空的情况下,上方代码obj->tail-1,就会造成0-1 == -1的情况。上方采用(obj->tail - 1+ obj->k+1)%(obj->k+1)就可以完美的避免,当然

其实可以写成

int myCircularQueueRear(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj))return -1;// return obj->a[(obj->tail-1 + obj->k+1)%(obj->k+1)];if(obj->tail == 0){return obj->a[obj->k];}else{return obj->a[obj->tail-1];}
}

8.循环队列释放

 因为用malloc开辟的动态内存空间,为了避免内存泄漏,我们还要释放内存。注意释放的顺序。

 代码:

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

三、完整代码展示:

 代码: 


//采用动态数组的形式来模拟循环队列
typedef struct {int* a;     //指向数组int front;  //队头int tail;   //队尾int k;      //数据个数
} MyCircularQueue;//创建长度为k的循环队列
MyCircularQueue* myCircularQueueCreate(int k) {//使用动态内存函数来申请内存//这里多申请一个空间的目的是防止假溢出//使用malloc创建一个循环队列MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));//为循环队列里面的指针a ,让a指向一个长度为k+1的数组obj->a= (int*)malloc(sizeof(int)*(k+1));obj->front = 0; //队头从数组的下标0开始obj->tail = 0; //队尾指向下一个元素obj->k = k; //队列的长度为kreturn obj;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {//队空,就是队头与队尾相同时return obj->front == obj->tail;
}bool myCircularQueueIsFull(MyCircularQueue* obj) {return (obj->tail+1)%(obj->k+1) == obj->front;
}//插入元素
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {//插入元素前先进行判断是否满if(myCircularQueueIsFull(obj)){return false;}//插入元素使用尾插obj->a[obj->tail] = value;obj->tail++;//避免tail的下标越界obj->tail%=(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; //队空返回-1}return obj->a[obj->front];
}//获取队尾元素
int myCircularQueueRear(MyCircularQueue* obj) {//队列不能为空if(myCircularQueueIsEmpty(obj)){return -1; //队空返回-1}//注意当tail = 0的情况return obj->a[(obj->tail - 1+ obj->k+1)%(obj->k+1)];
}void myCircularQueueFree(MyCircularQueue* obj) {free(obj->a);free(obj);
}/*** Your MyCircularQueue struct will be instantiated and called as such:* MyCircularQueue* obj = myCircularQueueCreate(k);* bool param_1 = myCircularQueueEnQueue(obj, value);* bool param_2 = myCircularQueueDeQueue(obj);* int param_3 = myCircularQueueFront(obj);* int param_4 = myCircularQueueRear(obj);* bool param_5 = myCircularQueueIsEmpty(obj);* bool param_6 = myCircularQueueIsFull(obj);* myCircularQueueFree(obj);
*/

相关文章:

Leetcode:622. 设计循环队列 题解【具详细】

目录 一、题目: 二、思路详解: 1.循环队列的存储定义 2.循环队列的创建 3.循环队列的判空与判断情况 (1) 循环队列的判空: (2) 循环队列的判满 4.循环队列元素的插入 5.循环队列元素的删除 6.获取队头元素 7.获取队尾元素 8.循环队列释放 三…...

ArkTS基础知识 【习题】

判断题 1.循环渲染ForEach可以从数据源中迭代获取数据,并为每个数组项创建相应的组件。 正确(True) 2. Link变量不能在组件内部进行初始化。 正确(True) 单选题 1.用哪一种装饰器修饰的struct表示该结构体具有组件化能力?(A) A. Component B. Entry C…...

是否有无限提取的代理IP?作为技术你需要知道这些

最近有互联网行业的技术小伙伴问到,有没有可以无限提取的代理IP?就是比如我一秒钟提取几万、几十万次,或者很多台机器同时调用API提取链接,这样可以吗?看到这个问题,不禁沉思起来,其实理论上是存…...

【算法萌新闯力扣】:卡牌分组

力扣热题:卡牌分组 一、开篇 今天是备战蓝桥杯的第22天。这道题触及到我好几个知识盲区,以前欠下的债这道题一并补齐,哈希表的遍历、最大公约数与最小公倍数,如果你还没掌握,这道题练起来! 二、题目链接:…...

深入解析:如何开发抖音票务小程序

当下,开发抖音票务小程序成为了吸引年轻用户群体的一种创新方式。本文将深入解析如何开发抖音票务小程序,探讨关键步骤和技术要点。 1.确定需求和功能 考虑到抖音的用户特点,可以加入与短视频相关的票务功能,如在线购票、观影记录…...

vue中 mixin用法

在Vue.js中,mixin是一种可以在多个组件之间共享Vue组件选项的灵活方式。mixin对象可以包含任何组件选项。当组件使用mixin时,所有mixin对象的选项将被“混合”到该组件的选项中。 使用mixin的一个主要优点是可以在多个组件之间重用和共享代码。这可以帮…...

Java入门基础:浅显易懂 while

文章目录 前言一、布尔表达式二、while三、语法四、示例 前言 在开发过程中不管是 while 语句还是其他语句都会经常用到布尔表达式,所以在学习 while 之前需要先明白什么是布尔表达式? 一、布尔表达式 布尔表达式只有2种结果:true / false 看…...

DNS/ICMP协议、NAT技术

目录 DNS协议DNS背景域名简介 ICMP协议ICMP功能ping命令traceroute命令 NAT技术NAT技术背景NAT IP转换过程NAPTNAT技术的缺陷NAT和代理服务器 网络协议总结应用层传输层网络层数据链路层 DNS协议 DNS(Domain Name System,域名系统)协议&…...

React整理总结(七、Hooks)

1.Class组件的优缺点 优点 class组件可以定义自己的state,用来保存组件自己内部的状态;函数式组件不可以,因为函数每次调用都会产生新的临时变量;class组件有自己的生命周期,我们可以在对应的生命周期中完成自己的逻…...

软件测试之银行测试详解

一、金融类软件测试 举个栗子,银行里的软件测试工程师。横向跟互联网公司里的测试来说,薪资相对稳定,加班的话想对来说没那么多(有些银行加班也挺严重的),但业务稳定。实在是测试类岗位中的香饽饽&#xf…...

C#中的警告CS0120、CS0176、CS0183、CS0618、CS8600、CS8602、CS8604、CS8625及处理

目录 一、CS0120 二、CS0176 1.解决前 2.解决后 3.解决办法 三、CS0183 四、CS0618 五、CS8600 六、CS8602 七、CS8622 1. 解决前: 2. 解决后: 3.解决方法: 八、CS8604和CS8625 一、CS0120 严重性 代码 说明 项目 文件 行…...

CSS:浏览器设置placeholder样式 / 微信小程序设置placeholder样式

一、web 设置placeholder 设置浏览器的placeholder样式 ::-webkit-input-placeholder { /* WebKit browsers */color: #999; } :-moz-placeholder { /* Mozilla Firefox 4 to 18 */color: #999; } ::-moz-placeholder { /* Mozilla Firefox 19 */color: #999; } :-ms-input-p…...

升级python后sudo apt-get update报错

sudo apt-get update 报错: sh: /usr/lib/cnf-update-db: /usr/bin/python3.7.5: bad interpreter: No such file or directory Reading package lists... Done E: Problem executing scripts APT::Update::Post-Invoke-Success if /usr/bin/test -w /var/lib/c…...

应用可观测性OpenTelemetry简介

应用可观测性OpenTelemetry简介 OpenTelmetry遥测方案可观测性三支柱日志 Logs指标跟踪 什么是OpenTelemetryOpenTelemetry架构和组件OpenTelemetry与OpenCensus、OpenTracing是什么关系 OpenTelmetry遥测方案 可观测性三支柱 日志 Logs 日志是特定事件在特定时间点发生的文本…...

install pnpm : 无法加载文件的解决办法

问题描述 我在使用pnpm的时候报错 PS D:\emss\pure-admin-backend> pnpm install pnpm : 无法加载文件 C:\Users\RD-16\AppData\Roaming\npm\pnpm.ps1。未对文件 C:\Users\RD-16\AppData\Roaming\npm\pnpm.ps1 进行数字签名。无法在当前系统上运 行该脚本。有关运行脚本和设…...

【Python百宝箱】Python数据探险:Excel与数据科学的完美结合

前言 在当今信息爆炸的时代,数据处理和分析已经成为各行各业不可或缺的一部分。在众多数据处理工具中,Python以其简洁而强大的语法成为数据科学家和分析师的首选之一。本文将深入探讨与电子表格处理相关的Python库,介绍它们的功能、应用场景…...

外贸分享|如何从外贸小白成长为大咖?这10件事值得你坚持做

外贸成功不是一朝一夕的事,而是需要有充分的准备和持续的努力。作为一位有着丰富经验的外贸人员,我总结了成功的秘诀,分享了一个优秀的外贸人应该做好的10项工作。 1 找不到客户怎么办? 有很多各种各样的原因值得思考&#xff1a…...

深度学习之六(自编码器--Autoencoder)

概念 自编码器(Autoencoder)是一种神经网络架构,用于无监督学习和数据的降维表示。它由两部分组成:编码器(Encoder)和解码器(Decoder)。 结构: 编码器(Encoder): 接收输入数据并将其压缩为潜在表示(latent representation),通常比输入数据的维度要低。编码器的…...

Docker Swarm总结+基础、集群搭建维护、安全以及集群容灾(1/3)

博主介绍:Java领域优质创作者,博客之星城市赛道TOP20、专注于前端流行技术框架、Java后端技术领域、项目实战运维以及GIS地理信息领域。 🍅文末获取源码下载地址🍅 👇🏻 精彩专栏推荐订阅👇🏻…...

Vim 一下日志文件,Java 进程没了?

一次端口告警,发现 java 进程被异常杀掉,而根因竟然是因为在问题机器上 vim 查看了 nginx 日志。下面我将从时间维度详细回顾这次排查,希望读者在遇到相似问题时有些许启发。 时间线 15:19 收到端口异常 odin 告警。 状态:P1故障 名称:应用端…...

国防科技大学计算机基础课程笔记02信息编码

1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制,因此这个了16进制的数据既可以翻译成为这个机器码,也可以翻译成为这个国标码,所以这个时候很容易会出现这个歧义的情况; 因此,我们的这个国…...

基于Docker Compose部署Java微服务项目

一. 创建根项目 根项目&#xff08;父项目&#xff09;主要用于依赖管理 一些需要注意的点&#xff1a; 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件&#xff0c;否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

css的定位(position)详解:相对定位 绝对定位 固定定位

在 CSS 中&#xff0c;元素的定位通过 position 属性控制&#xff0c;共有 5 种定位模式&#xff1a;static&#xff08;静态定位&#xff09;、relative&#xff08;相对定位&#xff09;、absolute&#xff08;绝对定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…...

04-初识css

一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

20个超级好用的 CSS 动画库

分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码&#xff0c;而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库&#xff0c;可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画&#xff0c;可以包含在你的网页或应用项目中。 3.An…...

基于IDIG-GAN的小样本电机轴承故障诊断

目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) ​梯度归一化(Gradient Normalization)​​ (2) ​判别器梯度间隙正则化(Discriminator Gradient Gap Regularization)​​ (3) ​自注意力机制(Self-Attention)​​ 3. 完整损失函数 二…...

抽象类和接口(全)

一、抽象类 1.概念&#xff1a;如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象&#xff0c;这样的类就是抽象类。 像是没有实际⼯作的⽅法,我们可以把它设计成⼀个抽象⽅法&#xff0c;包含抽象⽅法的类我们称为抽象类。 2.语法 在Java中&#xff0c;⼀个类如果被 abs…...

tauri项目,如何在rust端读取电脑环境变量

如果想在前端通过调用来获取环境变量的值&#xff0c;可以通过标准的依赖&#xff1a; std::env::var(name).ok() 想在前端通过调用来获取&#xff0c;可以写一个command函数&#xff1a; #[tauri::command] pub fn get_env_var(name: String) -> Result<String, Stri…...

算法打卡第18天

从中序与后序遍历序列构造二叉树 (力扣106题) 给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 示例 1: 输入&#xff1a;inorder [9,3,15,20,7…...