【数据结构】如何设计循环队列?图文解析(LeetCode)

LeetCode链接:622. 设计循环队列 - 力扣(LeetCode)

目录

做题思路

只开辟 k 个空间

多开一个空间

代码实现

1. 循环队列的结构

2. 开辟空间

3. 判断空

4. 判断满

5. 队尾插入数据

6. 队头删除数据

7. 获取队头元素

8. 获取队尾元素

9. 销毁队列

全部代码


做题思路

  • 设计循环队列,使用数组或链表都可以,各有优劣
  • 本文使用数组实现
  • 本文使用C语言实现

假设队列长度 k = 4

多开一块空间(开辟 k+1 块空间)可以方便区分空和满

为什么?

举个栗子:

只开辟 k 个空间

如果只开辟 k 个空间(假设 k = 4):

  • front(队头)
  • rear(队尾)
  • front 和 rear 初始都为 0

如果插入一个数据呢?

front 不变,rear 向后移动,如下图:

理想的判断空条件:

  • 队头 == 队尾,队列为空
  • 队头 != 队尾,队列非空

目前看来似乎可以正常判断队列是否为空

那如果队列满了呢?

如上图所示,队列满了

rear 又回到了 front 的位置

现在怎么判断满呢?

rear == front 吗?

似乎和前面判断空冲突了

想判断必须要特殊处理:比如加一个变量 size 来记录队列中元素的个数

这种方法虽然可以,但是会让代码显得很臃肿,于是我选择了另一种方法:

多开一个空间

如果多开了一个空间(开辟 k+1 个空间):

  • 这里多开的空间是不存放数据的
  • 这块空间存在的意义就是为了方便区分空和满

下面我将演示一下如何判断:

判断空:

  • 队头 == 队尾,队列为空
  • 队头 != 队尾,队列非空

判断满:

  • 队尾的下一个 == 队头,队列已满
  • 队尾的下一个 != 队头,队列未满

如下图:

那么好,这里简单介绍了一下我的实现思路:

  • 使用C语言实现
  • 使用数组实现
  • 数组多开一块空间

接下来就是详细的实现方法


代码实现

本题要求:

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

1. 循环队列的结构

//循环队列的结构
typedef struct
{int* a;     //一个数组int front;  //存放队头的下标int rear;   //存放队尾的下标int k;      //队列长度
} MyCircularQueue;

2. 开辟空间

//开辟空间并初始化
MyCircularQueue* myCircularQueueCreate(int k)
{MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));//多开一个方便区分空和满obj->a = (int*)malloc(sizeof(int) * (k + 1));obj->front = obj->rear = 0;obj->k = k;return obj;
}

3. 判断空

前面说过了,队头等于队尾时,队列为空

//检测循环队列是否为空
bool myCircularQueueIsEmpty(MyCircularQueue* obj)
{return obj->front == obj->rear;
}

4. 判断满

注意这里有一些坑点

前面说过:队尾+1等于队头时,队列为满

但是我用的是数组,不是链表队尾+1有可能会越界

如上图:rear+1 = 5,越界了

怎么办呢?可以采用取余数(%)的方法,即:(rear+1)%(k+1),让 rear+1 变回 0,达到循环的效果。

情况1:队尾+1越界了

(rear + 1) % (k + 1) = 0

front = 0

(rear + 1) % (k + 1) = front,说明循环队列已满。

情况2:队尾+1没越界

(rear + 1) % (k + 1) = 4

front = 0

(rear + 1) % (k + 1) != front,说明循环队列未满。

//检查循环队列是否已满
bool myCircularQueueIsFull(MyCircularQueue* obj)
{return (obj->rear + 1) % (obj->k + 1) == obj->front;
}

5. 队尾插入数据

这里需要一些操作,还是越界的问题,插入数据后队尾可能会越界,如下图:

rear 处插入数据后,rear 需要向后移动,导致越界

1)判断队列是否已满,满了是不能插入的,直接返回 false

2)在队尾插入数据

3)队尾++,可能会越界

4)依旧采用取余数的方法让队列循环起来,即:rear = rear % (k + 1)

//向循环队列插入一个元素。如果成功插入则返回真
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
{if (myCircularQueueIsFull(obj))return false;obj->a[obj->rear] = value;obj->rear++;obj->rear %= (obj->k + 1);return true;
}

6. 队头删除数据

删除数据后,队头也可能会有越界的情况,如下图:

删除 front 处的数据后,front 需要向后移动,导致越界

1)判断队列是否为空,空队列是不能删数据的,直接返回 false

2)删除数据很简单,直接让队头++即可

3)取余数避免越界:front = front % (k + 1)

//从循环队列中删除一个元素。如果成功删除则返回真
bool myCircularQueueDeQueue(MyCircularQueue* obj)
{if (myCircularQueueIsEmpty(obj))return false;obj->front++;obj->front %= (obj->k + 1);return true;
}

7. 获取队头元素

情况1:队列为空

根据题意,返回 -1

情况2:队列不为空

直接返回数组中下标为 front 的元素即可

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

8. 获取队尾元素

情况1:队列为空

根据题意,返回 -1

情况2:队列不为空

  • 需要返回数组中下标 rear 的前一个元素(rear-1
  • 此操作可能会导致越界
  • 用取余数的方式避免越界:(rear + k) % (k + 1)

如上图:这种情况下强行获取 rear 的前一个元素会导致越界

//获取队尾元素。如果队列为空,返回-1
int myCircularQueueRear(MyCircularQueue* obj)
{if (myCircularQueueIsEmpty(obj))return -1;elsereturn obj->a[(obj->rear + obj->k) % (obj->k + 1)];
}

9. 销毁队列

销毁所有动态开辟的空间

//销毁循环队列
void myCircularQueueFree(MyCircularQueue* obj)
{free(obj->a);free(obj);
}

全部代码

//循环队列的结构
typedef struct
{int* a;     //一个数组int front;  //存放队头的下标int rear;   //存放队尾的下标int k;      //队列长度
} MyCircularQueue;//开辟空间并初始化
MyCircularQueue* myCircularQueueCreate(int k)
{MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));//多开一个方便区分空和满obj->a = (int*)malloc(sizeof(int) * (k + 1));obj->front = obj->rear = 0;obj->k = k;return obj;
}//检测循环队列是否为空
bool myCircularQueueIsEmpty(MyCircularQueue* obj)
{return obj->front == obj->rear;
}//检查循环队列是否已满
bool myCircularQueueIsFull(MyCircularQueue* obj)
{return (obj->rear + 1) % (obj->k + 1) == obj->front;
}//向循环队列插入一个元素。如果成功插入则返回真
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
{if (myCircularQueueIsFull(obj))return false;obj->a[obj->rear] = value;obj->rear++;obj->rear %= (obj->k + 1);return true;
}//从循环队列中删除一个元素。如果成功删除则返回真
bool myCircularQueueDeQueue(MyCircularQueue* obj)
{if (myCircularQueueIsEmpty(obj))return false;obj->front++;obj->front %= (obj->k + 1);return true;
}//从队首获取元素。如果队列为空,返回-1
int myCircularQueueFront(MyCircularQueue* obj)
{if (myCircularQueueIsEmpty(obj))return -1;elsereturn obj->a[obj->front];
}//获取队尾元素。如果队列为空,返回-1
int myCircularQueueRear(MyCircularQueue* obj)
{if (myCircularQueueIsEmpty(obj))return -1;elsereturn obj->a[(obj->rear + obj->k) % (obj->k + 1)];
}//销毁循环队列
void myCircularQueueFree(MyCircularQueue* obj)
{free(obj->a);free(obj);
}

本文完

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

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

相关文章

炫酷的开关--20230907

Night && Day Toggle ☀️/&#x1f319; [Completed It!] HTML&#xff1a; <div class"controls"><label for"sync">Sync <body></label><input id"sync" type"checkbox"/> </div> &l…

基于javaweb的网上图书销售系统(servlet+jsp)

系统简介 本项目采用eclipse工具开发&#xff0c;jspservletjquery技术编写&#xff0c;数据库采用的是mysql&#xff0c;navicat开发工具。 角色&#xff1a; 管理员普通用户 模块简介 管理员&#xff1a; 登录用户管理图书分类管理图书管理图书订单管理图书评论管理数据统…

【通俗理解】CNN卷积神经网络 - 附带场景举例

一. CNN 算法概述 CNN的全称是Convolutional Neural Networks, ConvNets&#xff0c;称之为卷积神经网络&#xff0c;是深度学习的经典算法之一。 CNN一般用于图片分类、检索、人脸识别、目标定位等。在常规的图像处理的过程中&#xff0c;存在以下两个问题&#xff1a; 图像…

【2023高教社杯】D题 圈养湖羊的空间利用率 问题分析、数学模型及MATLAB代码

【2023高教社杯】D题 圈养湖羊的空间利用率 问题分析、数学模型及MATLAB代码 1 题目 题目 D 题 圈养湖羊的空间利用率 规模化的圈养养殖场通常根据牲畜的性别和生长阶段分群饲养&#xff0c;适应不同种类、不同阶段的牲畜对空间的不同要求&#xff0c;以保障牲畜安全和健康&a…

离线数仓同步数据3

业务数据_增量表数据同步 1&#xff09;Flume配置概述2&#xff09;Flume配置实操3&#xff09;通道测试4&#xff09;编写Flume启停脚本 1&#xff09;Flume配置概述 Flume需要将Kafka中topic_db主题的数据传输到HDFS&#xff0c;故其需选用KafkaSource以及HDFSSink&#xff…

内网穿透实现Windows远程桌面访问Ubuntu,简单高效的远程桌面解决方案

文章目录 前言1. ubuntu安装XRDP2.局域网测试连接3.安装cpolar内网穿透4.cpolar公网地址测试访问5.固定域名公网地址 前言 XRDP是一种开源工具&#xff0c;它允许用户通过Windows RDP访问Linux远程桌面。 除了Windows RDP外&#xff0c;xrdp工具还接受来自其他RDP客户端(如Fre…

uni-app 之 uni.request 网络请求API接口

uni-app 之 uni.request 网络请求API接口 image.png <template><!-- vue2的<template>里必须要有一个盒子&#xff0c;不能有两个&#xff0c;这里的盒子就是 view--><view>--- uni.request 网络请求API接口 ---<view><!-- 免费的测试接口 --…

制造企业如何优化物料控制?

导 读 ( 文/ 2127 ) 物料控制是指对制造过程中所涉及的物料流动和库存进行有效管理和控制的过程。它包括物料需求计划、供应商管理、物料采购、物料接收和入库、物料库存管理以及物料发放和使用等关键环节。通过精确的物料需求计划和库存管理&#xff0c;物料控制可以确保物料供…

转载: 又拍云【PrismCDN 】低延时的P2P HLS直播技术实践

低延时的P2P HLS直播技术实践本文是第二部分《PrismCDN 网络的架构解析,以及低延迟、低成本的奥秘》低延时的P2P HLS直播技术实践 [首页 > Open Talk NO.41 | 2018 音视频技术沙龙深圳站 > 低延时 WebP2P 直播技术实践https://opentalk-blog.b0.upaiyun.com/prod/2018-0…

【群答疑】jmeter关联获取上一个请求返回的字符串,分割后保存到数组,把数组元素依次作为下一个请求的入参...

一个非常不错的问题&#xff0c;来检验下自己jmeter基本功 可能有同学没看懂题&#xff0c;这里再解释一下&#xff0c;上面问题需求是&#xff1a;jmeter关联获取上一个请求返回的字符串&#xff0c;分割后保存到数组&#xff0c;把数组元素依次作为下一个请求的入参 建议先自…

TCP流量控制和拥塞控制,具体在场景中是怎么起作用的

TCP的流量控制 所谓的流量控制就是让发送方的发送速率不要太快&#xff0c;让接收方来得及接受。利用滑动窗口机制可以很方便的在TCP连接上实现对发送方的流量控制。TCP的窗口单位是字节&#xff0c;不是报文段&#xff0c;发送方的发送窗口不能超过接收方给出的接收窗口的数值…

《TCP/IP网络编程》阅读笔记--域名及网络地址

目录 1--域名系统 2--域名与 IP 地址的转换 2-1--利用域名来获取 IP 地址 2-2--利用 IP 地址获取域名 3--代码实例 3-1--gethostbyname() 3-2--gethostbyaddr() 1--域名系统 域名系统&#xff08;Domain Name System&#xff0c;DNS&#xff09;是对 IP 地址和域名进行相…

OLED透明屏模块:引领未来显示技术的突破

OLED透明屏模块作为一项引领未来显示技术的突破&#xff0c;以其独特的特点和卓越的画质在市场上引起了广泛关注。 根据行业报告&#xff0c;预计到2025年&#xff0c;OLED透明屏模块将占据智能手机市场的20%份额&#xff0c;并在汽车导航系统市场中占据30%以上份额。 那么&am…

安装K8s基础环境软件(二)

所有节点执行 1、安装docker sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.reposudo yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin systemctl…

Python web 框架web.py「简约美」

web.py is a web framework for Python that is as simple as it is powerful. web.py is in the public domain, you can use it for whatever purpose with absolutely no restrictions. web.py 是一个简单而强大的 Python Web 框架。web.py 属于公共领域&#xff0c;您可以…

《C++设计模式》——行为型

前言 行为型模式是对在不同的对象之间划分责任和算法的抽象化。行为型模式不仅仅关注类和对象的结构&#xff0c;而且重点关注它们之间的相互作用。 Interpreter(解释器) Template Method(模板方法) GOOD&#xff1a;把不变的代码部分都转移到父类中&#xff0c;将可变的代…

【深度学习实验】数据可视化

目录 一、实验介绍 二、实验环境 三、实验内容 0. 导入库 1. 归一化处理 归一化 实验内容 2. 绘制归一化数据折线图 报错 解决 3. 计算移动平均值SMA 移动平均值 实验内容 4. 绘制移动平均值折线图 5 .同时绘制两图 6. array转换为tensor张量 7. 打印张量 一、…

数据结构与算法:练习与实践的重要性

文章目录 为什么练习与实践很重要&#xff1f;1. 熟练应用2. 问题解决能力3. 代码效率4. 面试准备 如何练习与实践&#xff1f;1. 在线评测平台2. 自主设计数据结构3. 解决不同类型的问题 持续学习与实践 &#x1f389;欢迎来到数据结构学习专栏~数据结构与算法&#xff1a;练习…

【C++进阶(五)】STL大法--list模拟实现以及list和vector的对比

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:C从入门到精通⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习C   &#x1f51d;&#x1f51d; list模拟实现 1. 前言2. list类的大致框架与结构…

Linux下的系统编程——共享存储映射(十)

前言&#xff1a; mmap是一种内存映射文件的方法&#xff0c;即将一个文件或者其它对象映射到进程的地址空间&#xff0c;实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后&#xff0c;进程就可以采用指针的方式读写操作这一段内存&…