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

news2024/12/23 18:33:07

目录

一、题目:

二、思路详解:

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; //队列的长度为k
    return 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; //队列的长度为k
    return 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);
*/

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

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

相关文章

手写工作流设计模式,针对常见的工作流步骤流转,减少过多的if/else,提升编程思维

需求 这一年下来,写两次工作流流转,总结下经验。 第一次写的时候,只找到用模版设计模式包裹一下,每个方法都做隔离,但是在具体分支实现的时候,if/else 满屏分,而且因为要针对不同情况&#xff…

【TensorRT部署】pytorch模型(pt/pth)转onnx,onnx转engine(tensorRT)

1. 单帧处理 1. pt2onnx import torch import numpy as np from parameters import get_parameters as get_parameters from models._model_builder import build_model TORCH_WEIGHT_PATH ./checkpoints/model.pth ONNX_MODEL_PATH ./checkpoints/model.onnx torch.set_de…

毛里塔尼亚市场开发攻略,收藏一篇就够了

毛里塔尼亚是非洲西北部的一个国家,也是中国长期援建的一个国家,也是一带一路上的国家。毛里塔尼亚生产生活资料依赖进口,长期依赖跟我们国家的贸易关系也是比较紧密的,今天就来给大家介绍一下毛里塔尼亚的市场开发公路。文章略长…

“关爱零距离.情暖老人心”主题活动

为提高社区老年人的生活质量,促进邻里间的互动与友谊,以及弘扬尊老爱幼的社区精神,11月21日山东省潍坊市金阳公益服务中心、重庆市潼南区同悦社会工作服务中心在潼南区桂林街道东风社区共同在潼南区桂林街道东风社区举办了“关爱零距离.情暖老…

BMS实战: BMS产品介绍,电池外观分析,电芯种类分析,焊接方式分析,充电方式,电压平台,电芯型号分析。

快速入门的办法就是了解产品,了解现在市面上正在流通的成熟产品方案。光看基础知识是没有效果的。 首先我们找到了一张市面上正在出售的电池pack包。 图片来源网上,侵权删 电池外观分析 外壳: 一般是金属外壳,大部分都是铁壳加喷漆,特殊材质可以定制。 提手 一般是…

22款奔驰S400L升级主动式氛围灯 光影彰显奔驰的完美

新款奔驰S级原车自带64色氛围灯,还可以升级原厂的主动式氛围灯,增加车内的氛围效果。主动式环境氛围灯包含263个LED光源,每隔1.6厘米就有一个LED光源,照明效果较过去明亮10倍,视觉效果更加绚丽,它还可结合智…

怎么申请IP地址证书?

IP地址证书,也称为SSL证书,是一种数字证书,用于在网络传输过程中对IP地址进行加密和解密。它是由受信任的证书颁发机构(CA)颁发的,用于证明网站所有者身份的真实性和合法性。 一、选择证书颁发机构。首先需…

计算机是如何执行指令的

计算机组成 现在所说的计算机基本上都是冯诺依曼体系的计算机。其核心原理: 冯诺依曼计算的核心思想是将程序指令和数据以二进制形式存储存储在同一存储器中,并使用相同的数据格式和处理方式来处理它们。这种存储程序的设计理念使得计算机能够以可编程…

DataFunSummit:2023年因果推断在线峰会-核心PPT资料下载

一、峰会简介 因果推断是指从数据中推断变量之间的因果关系,而不仅仅是相关关系。因果推断可以帮助业务增长理解数据背后的机制,提高决策的效率和质量,避免被相关性误导,找到真正影响业务的因素和策略。 因果推断在推荐系统中的…

SpringBoot整合SpringSecurity+jwt+knife4生成api接口(从零开始简单易懂)

一、准备工作 ①&#xff1a;创建一个新项目 1.事先创建好一些包 ②&#xff1a;引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency>&…

时间敏感网络TSN的车载设计实践: 802.1Qbv协议

▎概述 IEEE 802.1Qbv[1]是TSN系列协议中备受关注的技术之一&#xff0c;如图1所示&#xff0c;它定义了一种时间感知整形器&#xff08;Time Aware Shaper&#xff0c;TAS&#xff09;&#xff0c;支持Qbv协议的交换机可以按照配置好的门控列表来打开/关闭交换机出口队列&…

某上市证券公司:管控文件交换行为 保护核心数据资产

客户简介 某上市证券公司成立于2001年&#xff0c;经营范围包括&#xff1a;证券经纪、证券投资咨询、证券承销与保荐、证券自营等。经过多年发展&#xff0c;在北京、上海、深圳、重庆、杭州、厦门等国内主要中心城市及甘肃省内各地市设立了15家分公司和80余家证券营业部。20…

字符串函数的模拟实现(strlen,strcpy,strcat,strcmp,strstr)(图文并茂,清晰易懂)

目录 1. strlen函数2. strcpy函数3. strcat函数4. strcmp函数5. strstr函数 个人专栏&#xff1a; 《零基础学C语言》 1. strlen函数 strlen函数&#xff08;Get string length&#xff09;的功能是求字符串长度 使用注意事项&#xff1a; 字符串以 ‘\0’ 作为结束标志&…

如何预防数据泄露?六步策略帮您打造企业信息安全壁垒

大家好&#xff01;我是恒小驰&#xff0c;今天我想和大家聊聊一个非常重要的话题——如何预防数据泄露。在这个数字化的时代&#xff0c;数据已经成为了我们生活中不可或缺的一部分。然而&#xff0c;随着数据的价值日益凸显&#xff0c;数据泄露的风险也随之增加。企业应该如…

windows电脑定时开关机设置

设置流程 右击【此电脑】>【管理】 【任务计划程序】>【创建基本任务】 gina 命令 查看 已经添加的定时任务从哪看&#xff1f;这里&#xff1a; 往下滑啦&#xff0c;看你刚才添加的任务&#xff1a;

Lora学习资料汇总

目录 LoRa联盟 Semtech lora网关供应商: LoRaMAC API文档 论坛 开发板 主流技术对比分析 LoRa网络距离模拟测试方法 LoRa应用 Lora LoraWAN教程 LoRa联盟 LoRa联盟&#xff1a;LoRaWAN规范的制定组织 https://www.lora-alliance.org/ LoRa技术白皮书&#xff1a;htt…

计算机毕业设计项目选题推荐(免费领源码)java+springboot+mysql 城市房屋租赁管理系统01855

摘 要 本论文主要论述了如何使用springboot 城市房屋租赁管理系统 &#xff0c;本系统将严格按照软件开发流程进行各个阶段的工作&#xff0c;采用B/S架构JAVA技术&#xff0c;面向对象编程思想进行项目开发。在引言中&#xff0c;作者将论述城市房屋租赁管理系统的当前背景以及…

SAP指针Field-Symbols:<FS>用法及实例

指针Field-Symbols:用法 内部字段定义 : FIELD-SYMBOLS: [TYPE>] 一、在ABAP编程中使用非常广泛&#xff0c;类似于指针&#xff0c;可以指代任何变量。 当不输入时&#xff0c;继承赋给它的变量的所有属性 当输入时&#xff0c;赋给它的变量必须与同类型。 举个简…

一文带你了解多文件混淆加密

目录 &#x1f512; 一文带你了解 JavaScript 多文件混淆加密 ipaguard加密前 ipaguard加密后 &#x1f512; 一文带你了解 JavaScript 多文件混淆加密 JavaScript 代码多文件混淆加密可以有效保护源代码不被他人轻易盗取。虽然前端的 JS 无法做到纯粹的加密&#xff0c;但通…

Grails 启动

Grails系列 Grails项目启动 文章目录 Grails系列Grails一、项目创建二、可能的问题1.依赖下载2.项目导入到idea失败3.项目导入到idea后运行报错 Grails Grails是一款基于Groovy语言的Web应用程序框架&#xff0c;它使用了许多流行的开源技术&#xff0c;如Spring Framework、…