循环队列+OJ题之设计循环队列

news2025/1/10 15:59:58

生命不是要等待风暴过去,而是要学会在风暴中跳舞。                ——卡莉尔·吉布朗
目录

🌺前言:

🍁一.循环队列是什么?

🍏二.循环队列有什么作用?

🍀三.OJ题之设计循环队列

1.创建循环队列的结构体

🏵️1.MyCircularQueue创建一个结构体指针

🍊3.myCircularQueueIsEmpty判断循环队列为空

🍀4.myCircularQueueIsFull判断循环队列为满

🍊5.myCircularQueueEnQueue往循环队列里面入元素 

🍂6.myCircularQueueDeQueue循环队列出元素 

🍁7.myCircularQueueFront返回对列头的元素

🍑8.myCircularQueueRear返回队列尾的元素

🍀9.myCircularQueueFree销毁循环队列

🍋四.完整代码


🌺前言:

之前我们学习了队列,队列是先进先出的一个结构,而且也写了几个OJ题了,想必对队列也是很熟悉了,之前也一直留了一个东西没有讲,那就是循环队列。今天就让我们一起来学习一下循环队列吧。

🍁一.循环队列是什么?

循环队列顾名思义,就是一个队列它是循环的,之前我们学习的单链表的队列,那么循环队列就可以是单向循环的单链表。
我们知道队列的结构可以链式的结构,也可以是顺序的结构。今天我们要讲的就是顺序结构的循环队列,顺序结构就是一个数组。

普通的顺序结构的队列:我们使用队头和队尾来记录元素的变化。

1.刚开始front和rear都指向数组的第一个位置,也就是下标为0的位置,初始化front和rear都为0,所以当front和rear相等的时候,那么即队列此时为空。

2. 此时我们可以入队列,也就是往队列里面入元素。入一个元素,rear就往后面走一步。

3.然后我们可以出队列,出一个元素,front就往后面加1。

如果我还要继续入队列就不行了,因为rear已经走到尾了,但是数组还没有满,这种情况我们就叫假溢出,然后循环队列就横空出世了,就是为了解决假溢出的问题。

🍏二.循环队列有什么作用?

循环队列就是为了解决队列假溢出的问题,可以更好的利用空间。
循环队列的逻辑结构:(注意逻辑结构是我们假象出来)

注意这里空的情况是front==rear,但是当我们入队列,把队列入满了之后,rear还是跑到了front的位置,这样就没法区分空和满的情况, 所以我们把队列的一个位置给空出来,不放元素使用,就是拿来区分满和空的情况,这种情况满了就rear+1==front。

知道了循环队列的用途,我们就来一个OJ题来练练手。

🍀三.OJ题之设计循环队列

题目描述:
设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 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

做题链接:循环队列
接口函数:

typedef struct {

} MyCircularQueue;


MyCircularQueue* myCircularQueueCreate(int k) {

}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {

}

bool myCircularQueueDeQueue(MyCircularQueue* obj) {

}

int myCircularQueueFront(MyCircularQueue* obj) {

}

int myCircularQueueRear(MyCircularQueue* obj) {

}

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {

}

bool myCircularQueueIsFull(MyCircularQueue* obj) {

}

void myCircularQueueFree(MyCircularQueue* obj) {

}

1.创建循环队列的结构体

typedef struct {
   int*a;//数组
   int front;//队列头
   int rear;//队列尾
   int k; //记录的队列的长度
} MyCircularQueue;

🏵️1.MyCircularQueue创建一个结构体指针

同样这里不是传参的方式,而是返回一个结构体的指针。

MyCircularQueue* myCircularQueueCreate(int k) {
   MyCircularQueue*obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
   obj->a=(int*)malloc(sizeof(int)*(k+1));
   //记住这里数组长度是k,但是我们开k+1个空间,剩下的一个空间就拿来判断满的
   obj->front=obj->rear=0;
   obj->k=k;
   return obj;
}

🍊3.myCircularQueueIsEmpty判断循环队列为空

判断循环队列尾空,那可就太简单了。rear==front即为循环队列为空。

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

🍀4.myCircularQueueIsFull判断循环队列为满

对于判断队列满了,还得仔细斟酌一下,难道就是rear+1==front就为满了吗,其实不是这样的,因为我们开始画的是循环队列的逻辑结构,只是为了我们好理解。实际情况可不这样的,循环队列实际就一个普通的数组,循环就体现在一些特殊的手段上面,这个手段就是取余。

这个确实是rear+1==front就满了,但是如果是下面的情况呢 

就无法通过rear+1==front来判断满了,所以我们要使用取余来使得rear的下标和front重合。 

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    return (obj->rear+1)%(obj->k+1)==obj->front;//取余操作使得下标重合
}

🍊5.myCircularQueueEnQueue往循环队列里面入元素 

直接往队列为入元素即可,满了就无法入元素了。

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
     if(myCircularQueueIsFull(obj))//当队列为满时,那么久无法入队列了,直接返回false
        return false;
    obj->a[obj->rear]=value;
    obj->rear++;
    obj->rear%=(obj->k+1);//同样是取余,达到循环的目的
    return true;
}

🍂6.myCircularQueueDeQueue循环队列出元素 

bool myCircularQueueDeQueue(MyCircularQueue* obj)
{
    if(myCircularQueueIsEmpty(obj))//队列为空,那么久无法出元素了,直接返回false
     return false;
     obj->front++;//队列头往后走,即是出元素
     obj->front%=(obj->k+1);
     return true;
}

🍁7.myCircularQueueFront返回对列头的元素

int myCircularQueueFront(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))//为空,返回-1
       return -1;
    return obj->a[obj->front];
}

🍑8.myCircularQueueRear返回队列尾的元素

int myCircularQueueRear(MyCircularQueue* obj) {  
    if(myCircularQueueIsEmpty(obj))
       return -1;
       return obj->a[(obj->rear+obj->k)%(obj->k+1)];//这里是尾,同样要使用取余来循环
}

🍀9.myCircularQueueFree销毁循环队列

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));
   //记住这里数组长度是k,但是我们开k+1个空间,剩下的一个空间就拿来判断满的
   obj->front=obj->rear=0;
   obj->k=k;
   return obj;
}

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

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

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
     if(myCircularQueueIsFull(obj))//当队列为满时,那么久无法入队列了,直接返回false
        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;
}

int myCircularQueueFront(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))//为空,返回-1
       return -1;
    return obj->a[obj->front];
}

int myCircularQueueRear(MyCircularQueue* obj) {  
    if(myCircularQueueIsEmpty(obj))
       return -1;
       return obj->a[(obj->rear+obj->k)%(obj->k+1)];//这里是尾,同样要使用取余来循环
}

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

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

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

相关文章

实战演练 | Navicat 数据生成功能

数据生成的目的是依据某个数据模型,从原始数据通过计算得到目标系统所需要的符合该模型的数据。数据生成与数据模型是分不开的,数据生成的结果应该符合某个数据模型对于数据的具体要求。所以,随着数据模型的发展,数据生成的方法相…

window 利用Qt-windeployqt打包exe程序 一个简单的实例

用一个简单的实例展示下window 如何使用QT-windeployqt打包exe程序使得其可以在别的电脑上运行 一、release模式获得exe可执行文件 新建一个QT项目 构建选择使用CMake base class选择QMainWindow Kit Selection一定要注意,我选的是MinGW 32-bit UI设计 mainwindow.…

手机充电宝电子充气泵方案

该充气泵产品方案的运行原理是通过电动机将电能转化为机械能,带动电机做往复运动,从而产生大量压缩空气,达到快速充气的效果。该充气泵可用于气垫床、汽车轮胎、自行车轮胎、足球、游泳圈等各类充气物品。产品设计以人性化为主,简…

VMware重新安装后没有VMnet1和VMnet8网络

问题: VMware重新安装后,没有自动生成VMnet1和VMnet8网络, 并且使用VMware自带的虚拟网络编辑器也无法生成。 导致主机无法ping通虚拟机。 如下图:点击该选项,然后应用,转一会圈也没有产生对应的网络适配器。 问题原…

物联网技术助力物流智能化:从货物追踪到配送优化

目录 前言 物流领域的IoT设备 物流领域的应用 二、仓库管理 三、物流配送 IoT组合应用 区块链在物流领域应用 展望 前言 随着全球贸易和物流业的快速发展,物流领域的智能化和自动化已成为不可避免的趋势。而物联网技术作为一种重要的数字技术,已经在物流…

VIsual Studio内引用Lua解释器,编译Lua源码,执行Lua脚本

前言 本篇在讲什么 在Visual Studio中引入lua的解释器 使用C调用Lua文件 本篇适合什么 适合初学Lua的小白 适合需要C/C和lua结合开发的人 本篇需要什么 对Lua语法有简单认知 对C/C语法有简单认知 依赖Lua5.1的环境 依赖VS 2017编辑器 本篇的特色 具有全流程的图文…

Shellcode分离加载实现免杀的两种方式(VT免杀率:1/68)

简介 本文详细介绍了如何通过文件加载和远程URL加载方式实现Shellcode分离加载,以规避安全软件的检测。文章首先描述了通过Metasploit Framework生成的shellcode文件加载的过程,并提供了相关的C代码。 为了避免被杀毒软件检测,利用动态API调…

自动化测试-DevOps如何实施?看看10年测试大佬的总结...

目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 Selenium4自动化测…

2023最新!软件测试高频面试题基础知识点分享

近期也算是抽取出大部分休息的时间,为大家准备了一份通往大厂面试的小捷径,准备了一整套软件测试复习面试的刷题以及答案,我知道很多同学不知道怎么复习,不知道学习过程中哪些才是重点,其实,你们经历过的事…

内网渗透(八十二)之 CVE-2019-1040 NTLM MIC 绕过漏洞

CVE-2019-1040 NTLM MIC 绕过漏洞 漏洞背景 2019年6月11日,微软发布6月份安全补丁更新。在该安全补丁更新中,对 CVE-2019-1040 漏洞进行了修复。该漏洞存在于Windwos 大部分版本中,当中间人攻击者能够成功绕过NTLM 消息完整性校验(MIC)时,Windows 存在可能可篡改的漏洞…

R语言实践——rWCVP生成可发表级别的物种发现记录矩阵

rWCVP生成可发表级别的物种发现记录矩阵 介绍1. 查询一组示例数据2. 生成和格式化出现矩阵3. 额外地对国家进行处理 介绍 世界维管植物名录(WCVP)提供了已知的>340,000种维管植物物种的分布数据。该分布数据可用于构建植物物种名录的发现…

解密报错-java.security.InvalidKeyException: Illegal key size(本机解密正常,服务器解密报错)

记录在对接微信接口时需要的问题,对微信消息进行解密时报错,在本地进行解密是正常的,但部署到服务器进行解密就会报错 报错信息 java.security.InvalidKeyException: Illegal key sizeat javax.crypto.Cipher.checkCryptoPerm(Cipher.java:…

windows 系统扩容C盘注意事项

windows系统大家都不陌生,是大家用的最多的操作系统。在实际的使用中,遇到需要扩容C盘的情况不是很多,但是如果遇到了,有以下几个事项需要大家注意: 剩余空间是否充足 不论当前服务器是物理服务器还是虚拟机&#xff…

Slack工作区SolidUI 集成Claude使用流程,替代GPT3.5

背景 Claude 由 OpenAI 副总裁离职创立的和chatGPT对位的AI机器人,号称是chatGPT一生的对手! 比之前的一些模型如GPT-3 要强大得多,因此Claude 被认为是ChatGPT 最有力的竞争对手。Claude 的研发公司是专注人工智能安全和研究的初创公司Anth…

谷歌Bard_VS_Baize-7B_VS_文心一言体验对比

2023年4月4日,来自加州大学圣迭戈分校、中山大学和微软亚研的研究者提出了Baize,该模型是让ChatGPT 自我对话,批量生成高质量多轮对话数据集,利用该数据集对LLaMA进行微调得到的(目前版本还没有RLHF) 关于B…

使用Dockerfile搭建rtthread 瑞萨开发环境

文章目录 1. 装docker2. 拉代码3. 构建镜像4. 启动容器5. vscode打开并编译6. 程序下载 整体分为6步 安装docker拉取rtthread_瑞萨仓库代码使用仓库中的dockerfile构建一个镜像使用构建好的镜像启动一个容器使用vscode打开并编译代码下载程序 1. 装docker Docker的安装方式可…

vue自动更新版本号

在项目中创建buildTime.js //npm run build打包前执行此段代码 let fs require(fs); //返回package的json数据 function getPackageJson() { let data fs.readFileSync(./package.json);//fs读取文件 return JSON.parse(data);//转换为json对象 } let packageData getPackag…

FreeRTOS_中断配置和临界段

目录 1. Cortex-M 中断 1.1 中断简介 1.2 中断管理简介 1.3 优先级分组定义 1.4 优先级设置 1.5 用于中断屏蔽的特殊寄存器 1.5.1 PRIMASK 和 FAULTMASK 寄存器 1.5.2 BASEPRI 寄存器 2. FreeRTOS 中断配置宏 2.1 configPRIO_BITS 2.2 configLIBRARY_LOWEST_INTERRU…

IOC(控制反转)

目录 理解IOC 理解IOC容器 Spring IOC IOC优点 什么是依赖注入DI DI是如何实现的呢? 总结 : IOC实现的基本过程 容器如何放入Bean对象? IOC实现的基本过程 IoC容器在Spring的实现 理解IOC IoC 是 Inversion of Control 的简写,译为“控制反…

容器部署 redis 哨兵集群 【问题笔记】

目录 1.哨兵模式 (sentinel) 启动时报错:Cant resolve instance hostnames 2.哨兵模式下 master 节点崩掉后无法切换从节点为master节点 1.哨兵模式 (sentinel) 启动时报错:Cant resolve instance hostna…