环环相扣,循环不止:深入解析循环队列

news2025/1/9 15:05:34

在这里插入图片描述
本盘博客会讲解力扣“622. 设计循环队列”的解题思路,这是题目链接。

先来审下题:
在这里插入图片描述
以下是示例:
在这里插入图片描述
以下是提示:
在这里插入图片描述
如何设计一个循环队列呢?这里我用数组来实现。结构的定义如下:

typedef struct {
    int* a;    // 存储数据的数组
    int k;     // 最多存储的有效数据个数
    int front; // 队头
    int rear;  // 队尾
} MyCircularQueue;

接下来分析如何入队列、出队列、判空、判满、取队头和队尾的数据。在不考虑越界的情况下,大概的逻辑是:

  1. 数组初始化的空间能够存储k+1个数据。
  2. 入队列时,我们在rear的位置插入数据,接着rear加1,所以rear标识的是最后一个数据的下一个位置。
  3. 出队列时,我们让front加1即可。
  4. 若front和rear相等,则队列为空。
  5. 若rear加1后和front相等(front是rear的下一个),则队列为空。
  6. 队头数据是下标为front的数据。
  7. 队尾数据是下标为rear-1的数据。

但以上说法是有瑕疵的,因为加1后有可能向后越界,减1后有可能向前越界,这就需要进行特殊的处理,体现循环队列的特色:首尾相接,当向后越界时,会重新回到0;向前越界时,会来到数组的最后。具体的操作可以使用判断语句,比如当下标超出数组长度时,把下标置成0,不过我更喜欢使用取模的方式,这点后面会讲解。

初始化时,数组a的大小应该能够存储k+1个数据,也就是说,其中一个位置会空出来。为什么要这样处理呢?因为若数组只能容纳k个数据,判空和判满的条件就都是rear+1 == front,就无法区分空和满了。

MyCircularQueue* myCircularQueueCreate(int k) {
    // 开空间
    MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    // 数组开k+1个空间
    obj->a = (int*)malloc(sizeof(int) * (k + 1));
    // 初始化
    obj->k = k;
    obj->front = 0;
    obj->rear = 0;

    return obj;
}

入队列时,先要判断是否已满,满了就不能继续入队列了。接着插入数据,在rear的位置插入数据value,然后更新队尾rear。注意:不能简单的更新为rear+1,因为有可能越界,所以还要mod数组的长度,即(rear+1)%(k+1)。取模的效果是:当rear和k+1相等时,已经越界了,就会绕回去,重新变成0。后面的函数中,取模的效果是类似的。

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    // 满了就不能入队列
    if (myCircularQueueIsFull(obj))
        return false;

    // 插入数据
    obj->a[obj->rear] = value;
    // 更新队尾 = (旧队尾+1) % 容量
    obj->rear = (obj->rear + 1) % (obj->k + 1);
    return true;
}

出队列时,应该先判断是否为空,若空了就不能出队列了。接着,让队头front加1,但是和前面类似,还要mod数组的长度,防止越界。

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    // 空了就不能出队列
    if (myCircularQueueIsEmpty(obj))
        return false;

    // 更新队头 = (旧队头+1) % 容量
    obj->front = (obj->front + 1) % (obj->k + 1);
    return true;
}

取队头数据时,应该先判断是否为空,若未空则不能取队头数据。返回队头数据时,由于front就是队头,直接返回即可。

int myCircularQueueFront(MyCircularQueue* obj) {
    // 空了就返回-1
    if (myCircularQueueIsEmpty(obj))
        return -1;

    // 返回队头元素
    return obj->a[obj->front];
}

取队尾数据就有讲究了。首先判空,不必多说。接着返回队尾数据,而tail标识队尾数据的下一个位置,所以应返回rear-1位置的数据。但是减1后有可能变成负数,所以还要加上数组长度再取模,最终的下标是(rear-1 + k+1) % (k+1)。为什么不能直接取模呢?因为当对一个负数取模时,效果并不是我们想要的,我们应该尽量避免对负数取模。

int myCircularQueueRear(MyCircularQueue* obj) {
    // 空了就返回-1
    if (myCircularQueueIsEmpty(obj))
        return -1;

    // 返回队尾元素,下标为:(队尾-1+容量) % 容量
    //return obj->a[(obj->rear - 1 + obj->k + 1) % (obj->k + 1)];
    return obj->a[(obj->rear + obj->k) % (obj->k + 1)];
}

front==rear,则队列为空。

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    // 队尾 == 队头
    return obj->rear == obj->front;
}

rear+1 == front,则队列已满。但是直接这么判断是不对的,因为rear加1后有可能越界,所以要mod数组的长度再判断。

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    // (队尾+1) % 容量 == 队头
    return (obj->rear + 1) % (obj->k + 1) == obj->front;
}

销毁队列,只需销毁结构体中的成员,再销毁结构体即可。

void myCircularQueueFree(MyCircularQueue* obj) {
    // 释放空间
    free(obj->a);
    obj->a = NULL;
    obj->k = 0;
    obj->front = 0;
    obj->rear = 0;
    free(obj);
    obj = NULL;
}

完整的代码如下:

typedef struct {
    int* a;    // 存储数据的数组
    int k;     // 最多存储的有效数据个数
    int front; // 队头
    int rear;  // 队尾
} MyCircularQueue;


MyCircularQueue* myCircularQueueCreate(int k) {
    // 开空间
    MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    // 数组开k+1个空间
    obj->a = (int*)malloc(sizeof(int) * (k + 1));
    // 初始化
    obj->k = k;
    obj->front = 0;
    obj->rear = 0;

    return obj;
}

bool myCircularQueueIsFull(MyCircularQueue* obj);

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    // 满了就不能入队列
    if (myCircularQueueIsFull(obj))
        return false;

    // 插入数据
    obj->a[obj->rear] = value;
    // 更新队尾 = (旧队尾+1) % 容量
    obj->rear = (obj->rear + 1) % (obj->k + 1);
    return true;
}

bool myCircularQueueIsEmpty(MyCircularQueue* obj);

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    // 空了就不能出队列
    if (myCircularQueueIsEmpty(obj))
        return false;

    // 更新队头 = (旧队头+1) % 容量
    obj->front = (obj->front + 1) % (obj->k + 1);
    return true;
}

int myCircularQueueFront(MyCircularQueue* obj) {
    // 空了就返回-1
    if (myCircularQueueIsEmpty(obj))
        return -1;

    // 返回队头元素
    return obj->a[obj->front];
}

int myCircularQueueRear(MyCircularQueue* obj) {
    // 空了就返回-1
    if (myCircularQueueIsEmpty(obj))
        return -1;

    // 返回队尾元素,下标为:(队尾-1+容量) % 容量
    //return obj->a[(obj->rear - 1 + obj->k + 1) % (obj->k + 1)];
    return obj->a[(obj->rear + obj->k) % (obj->k + 1)];
}

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    // 队尾 == 队头
    return obj->rear == obj->front;
}

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    // (队尾+1) % 容量 == 队头
    return (obj->rear + 1) % (obj->k + 1) == obj->front;
}

void myCircularQueueFree(MyCircularQueue* obj) {
    // 释放空间
    free(obj->a);
    obj->a = NULL;
    obj->k = 0;
    obj->front = 0;
    obj->rear = 0;
    free(obj);
    obj = NULL;
}

在这里插入图片描述
轻松通过。

总结

循环队列的下标操作需要小心越界,若有可能越界,则要采取下面的处理:

  1. 若下标大于数组范围,则要mod数组长度。
  2. 若下标小于0,则要先加数组长度,再mod数组长度。

感谢大家的阅读!

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

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

相关文章

又一神器开源!无需服务器支持!打通手机,浏览器的Web LLM!

大家好,我是千与千寻,大家可以叫我“千寻哥”,之前和大家分享了两篇关于ChatGPT的技术文章: 1.chatgpt 2.chatgpt ChatGPT毫无疑问是现在最大的风口,各个行业都在集成ChatGPT的API接口以及各类的应用插件&#xff0…

本地部署 GPT Academic

本地部署 GPT Academic GPT Academic 项目概述Github 地址部署 GPT Academic配置 GPT Academic 参数启动 GPT Academic访问 GPT AcademicNew Bing Cookie 的获取方法 GPT Academic 项目概述 GPT 学术优化 (GPT Academic),为GPT/GLM提供图形交互界面,特别…

SSM整合(单元测试、结果封装、异常处理)

文章目录 1,SSM整合1.1 流程分析1.2 整合配置步骤1:创建Maven的web项目步骤2:添加依赖步骤3:创建项目包结构步骤4:创建SpringConfig配置类步骤5:创建JdbcConfig配置类步骤6:创建MybatisConfig配置类步骤7:创建jdbc.properties步骤8:创建SpringMVC配置类步…

【Leetcode刷题】算法:最长公共前缀

文章目录 一、题目描述二、解题思路2.1 解法12.2 解法22.3 解法32.4 解法4 三、结果提交 一、题目描述 二、解题思路 2.1 解法1 class Solution:def longestCommonPrefix(self, strs: List[str]) -> str:if not strs: # 如果字符串数组为空,则返回空字符串ret…

MIL-STD-1553B总线系统搭建指导

MIL-STD-1553B总线系统搭建指导 1.1553B总线协议 1.11553B总线介绍 MIL-STD-1553B(GJB 289A)是一种应用于机载电子设备间通信的共享式总线通信协议,以总线式拓扑结构连接最多31个终端设备互联,传输速率为1Mbps,在航…

任务跟踪器重要性探析:提升项目效率,实现管理优化

使用任务跟踪器完成项目的最显著好处之一是它们大大减少了开始新项目的初始阻力,尤其是当它们是大型、长期和复杂的项目时。任务跟踪器可用于将这些艰巨的项目分解为更小的、相互依赖的任务,这些任务有助于激发动力和行动以实现最终目标。使用项目任务跟…

Python: 让单元测试输出像GoogleTest一样

文章目录 1. 目的2. 原版 unittest 的输出3. 仿 GoogleTest 的输出效果4. 实现原理浅析传入 testRunner 参数testRunner 参数应该满足的条件颜色高亮: ASCII 转义字符的使用测试用例输出文本内容的格式调整:仿googletest 5. 完整实现代码6. 完整调用代码…

$‘\r‘: command not found syntax error near unexpected token `$‘do\r‘‘ 解决方案

问题描述 今天在执行代码时出现了这样的错误: bash xxx.sh xxx.sh: line 2: $\r: command not found xxx.sh: line 7: $\r: command not found xxx.sh: line 8: syntax error near unexpected token $do\r 经查阅,发现是.sh文件在windows下编辑&#xf…

Nevron Open Vision for .NET Crack

Nevron Open Vision for .NET Crack 增加了对Microsoft.NET 7.0的支持-NOV现在完全支持.NET Core 7.0,此外还支持Microsoft.NET Framework 4.7.2、.NET Core 5.0和.NET Core 6.0的内部版本。 用于.NET改进的NOV图表 添加了WPF和WinForms版本中提供的新3D渲染引擎。新…

展会回顾 | 2023元宇宙生态博览会圆满落幕,3DCAT荣获“元宇宙交互技术奖”

2023年5月10日-5月12日,一场涵盖了元宇宙终端头显、数字文娱、数字艺术、数字运动、数字多媒体展陈设计、数字展厅展馆、科技文旅、夜游演艺、沉浸式KTV/酒吧等多个领域的元宇宙商业盛会——2023第2届世界元宇宙生态博览会在广州广交会展馆A区3.2馆、4.2馆掀开帷幕。…

Python求balance_list【三】

本文为博主原创,未经授权,严禁转载及使用。 本文链接:https://blog.csdn.net/zyooooxie/article/details/130159648 很早之前,我写了2篇 如何求balance_list 的博客: https://blog.csdn.net/zyooooxie/article/detail…

DeepFM - 工业界经典baseline(哈工大 华为)

文章目录 1、模型结构如下:2、关键理解点:3、代码实现细节:DeepFM: A Factorization-Machine based Neural Network for CTR Prediction。dfm由哈工大和华为合作发表在IJCAI-2017;模型结构很简单,wide&deep结构。1、模型结构如下: 相比wide&deep [下文简称wd] 有…

就业内推 | 应届生校招、实习,上市公司有岗,最高18k*15薪

01 UCloud 🔷招聘岗位:网络工程师 🔷职责描述: 1、负责UCloud全球骨干网或数据中心网络工作,包括设备技术选型、架构运营方案设计、日常运维支持 2、持续提升网络稳定性与性能。 🔷任职要求: …

Flowable-modeler可视化教程

Flowable-Modeler功能 提供可视化编辑器,编辑BPMN流程,编辑CASE模型,编辑Form表单,编辑App应用,编辑决策表提供可视化参数配置:每个流程可以配置详细的参数设置,按照流程对应的规范来设计。提供…

学Python的都在说爬虫容易进去,你还敢做爬虫吗?十分钟带你规避可拷风险

阅读文本大概需要 10 分钟,今天,不要面向监狱编程了。 序言 前段时间有一篇名为《只因写了一段爬虫,公司200多人被抓!》的文章非常火,相信大家应该都看到了。 这篇文章火起来之后,本来经过了一个多月的时…

【Spring框架】--01.Spring概述、入门

文章目录 Spring1.概述1.1Spring是什么?1.2 Spring 的狭义和广义1.3 Spring Framework特点1.4 Spring模块组成1.5 Spring6特点1.5.1版本要求 2.入门2.1 构建模块2.2 程序开发2.2.1 引入依赖2.3.2 创建java类2.3.3 创建配置文件2.3.4 创建测试类测试2.3.5 运行测试程…

centos上搭建redis伪集群

1.安装ruby 搭建redis集群需要ruby脚本,需要安装ruby的环境 (1)yum install ruby (2) yum install rubygems 2. 复制安装完成的redis /usr/local目录下创建redis-cluster目录,复制已经安装完成的redis到 /usr/local/redis-cluster/redis01目录&#x…

京东软件测试岗位经典面试题(附答案)

1、黑盒测试的测试用例常见设计方法都有哪些?请分别以具体的例子来说明这些方法在测试用例设计工作中的应用。 1)等价类划分:等价类是指某个输入域的子集合.在该子集合中,各个输入数据对于揭露程序中的错误都是等效的.并合理地假…

【从零开始写视觉SLAM】v0.1基于特征点的简单VO

v0.1版本的oSLAM实现了基于orb特征点的简单视觉里程计,通过连续两帧的rgbd数据实现相机相对位姿的估计。 #mermaid-svg-ibQfHFVHezQD5RWW {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-ibQfHFVHezQD5RW…

MySQL数据库---笔记1

MySQL数据库---笔记1 一、数据库概述1.1、什么是数据库1.2、数据库的安装与启动1.3、MySQL数据模型 二、SQL2.1、通用语法及分类2.2、DDL2.2.1、数据库操作 一、数据库概述 1.1、什么是数据库 名称全称简称数据库存储数据的仓库,数据是有组织的进行存储DataBase (…