【初阶数据结构】深入解析循环队列:探索底层逻辑

请添加图片描述

🔥引言

本篇将介绍如何实现循环队列并实现过程需要注意的事项,虽然篇幅较小,但是其中逻辑还是值得引人思考的,循环队列可以采用数组或链表实现,这篇将采用数组实现循环队列

请添加图片描述
Alt

🌈个人主页:是店小二呀
🌈C语言笔记专栏:C语言笔记
🌈C++笔记专栏: C++笔记
🌈初阶数据结构笔记专栏: 初阶数据结构笔记

🌈喜欢的诗句:无人扶我青云志 我自踏雪至山巅
请添加图片描述

文章目录

  • 一、循环队列的概念
  • 二、实现循环队列的知识铺垫(核心实现逻辑)
    • 2.1 队列满足什么条件为空
    • 2.2 解决何时为空何时为满的方案
    • 2.3 小总结
    • 2.4 循环队列中如何保证闭环
    • 2.5 计算循环队列的数据个数
  • 三、实现循环队列相关步骤
    • 3.1 循环队列的搭建
    • 3.2 构建器(设置队列长度为 k)
    • 3.3 判断循环队列是否为满和空的情况
    • 3.4 检查是否能插入数据和删除数据
    • 3.5 获得队首元素和队尾元素
    • 3.6 循环的销毁

一、循环队列的概念

循环队列是一种用数组实现的队列数据结构,与普通队列不同的是,循环队列允许队列的头尾相接,实现循环利用数组空间。它解决了普通队列在出队操作频繁时需要大量元素迁移的效率问题。循环队列通常通过两个指针来实现:一个指向队列的头部(front),一个指向队列的尾部(rear)。当队列满时,rear 指针可以绕回到数组的起始位置,实现循环存储;当队列为空时,front 和 rear 指针指向同一个位置。

在这里插入图片描述

在这里插入图片描述

二、实现循环队列的知识铺垫(核心实现逻辑)

2.1 队列满足什么条件为空

当front==back时不一定为空。这里是循环队列,如果出现front= =back时会出现下列两种情况

  • back通过循环与front相遇,此时front==back,则队列满了
  • 一开始back没有移动,back和front在同位置,此时front==back,则队列为空

对此我们无法通过front==back区分开空和满的情况,需要重新定义为空或满的标志

2.2 解决何时为空何时为满的方案

关于front和back初始位置,front指向对头,而由于back指向队尾会很难看,需要手动back置为-1,对此这里back指向队尾的下一个元素(跟栈中top定义问题是类似的)

判断满的两种方案:

  • 增加一个size,当front== back并且size= =0就为空,size!=0就是为满
  • 多开一个空间,这样的好处就是back+1==front为满(不要存储数据,这样又回到了不能判断空或满)

2.3 小总结

这里我们选择第二种方案进行实现,对此我们总结下,定义好的方式。

  1. front == back就是为空
  2. back + 1 == front就是为满

2.4 循环队列中如何保证闭环

如果遇到循环相关问题,可以考虑取模(解决问题上十分巧妙)。我们想要达到的目的是当back到达空位置时,就是相当于到了头位置。

同时取模中,如果左边小于右边,没有改变。如果左边大于左边,就会删除右边的倍数,直到左边小于右边(这里就是取模的逻辑,如果很难理解,可以通过图来理解下)

在这里插入图片描述

在这里插入图片描述

这里需要注意的是:这张图我们需要关注的地方back + 1和 head的位置k +1是空位置下标为4和0位置重叠处三处。这里size为有效元素个数,这里只多开一个空间并没有算上有效元素,然后k + 1到达空位置,我们想要的结果是我们想要达到的目的是当back到达空位置时,就是相当于到了头位置,这里(obj->back+1)%(obj->size+1)==obj->head;就满足了这种情况,相同数据取模模为0,意味着下标为0

2.5 计算循环队列的数据个数

如果是计算队列的数据个数,通常就是back - front,但是这里是循环队列可能会出现back在front前面的特殊情况。

在这里插入图片描述

解决措施:(back+(k+1)-front)%k+1。这里担心back - front出现负数,个数不是存在负数这种情况的。那么可以将back + (k + 1) - front % k + 1这样保证了back - front + (k + 1) % k + 1当back - front出现负数,增加k + 1保证了正数再取模保证数据没有超过循环队列的长度,那么这样得到数据个数是否正确呢?通过画图在整个循环中的代表位置是相同的。

只要理解上面相关知识,模拟实现循环队列也变得简单起来了,让我们模拟实现起来吧!

三、实现循环队列相关步骤

3.1 循环队列的搭建

typedef struct
{
    int *a;
    int size;
    int head;
    int back;//元素的下一个位置
} MyCircularQueue;
//head 和 back都为下标

这里需要注意的是:这里没有跟队列一样采用两个结构体设计,而是采用在结构体对象内开辟一块空间用于存储节点,再调用结构体成员进行头尾操作,达到循环队列的功能。

3.2 构建器(设置队列长度为 k)

MyCircularQueue* myCircularQueueCreate(int k) //为结构体开辟空间
{   
    MyCircularQueue *obj=(MyCircularQueue *)malloc(sizeof(MyCircularQueue));
    if(obj==NULL)
    return NULL;
    obj->a=(int *)malloc(sizeof(int)*(k+1));//多开一个空间
    if(obj->a==NULL)
    return NULL;

    obj->size=k;
    obj->back=obj->head=0;

    return obj;
}

这里需要注意的是:关于两次调用malloc函数开辟空间,第一次malloc开辟空间,用于为该结构体对象开辟空间,第二次malloc开辟空间,是为了队列元素开辟空间(包含了不存放数据的空间),这空间是关联在一起的,对此需要搞清楚需要开辟多大的空间和交给什么数据类型维护

3.3 判断循环队列是否为满和空的情况

bool myCircularQueueIsFull(MyCircularQueue* obj) 
{
    return (obj->back+1)%(obj->size+1)==obj->head;
}

bool myCircularQueueIsEmpty(MyCircularQueue* obj) 
{
    assert(obj);
    return obj->head==obj->back;
}

这里需要注意的是:对于判断是否为空,不是重点,对于判断是否为满,根据取模的特点进行处理,对于数据结构处理建议画图分析

3.4 检查是否能插入数据和删除数据

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
 {
    if(myCircularQueueIsFull(obj))
    return false;

    obj->a[obj->back]=value;
    obj->back++;

    //防止越界
    obj->back%=(obj->size+1);
    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj)
{
    if(myCircularQueueIsEmpty(obj))
    return false;

    obj->head++;
    //防止越界
    obj->head%=(obj->size+1);
    return true;
}

这里需要注意的是:这里无论是插入还是删除数据,需要对x %= (obj->size+1);防止超过队列长度,而且这里需要注意顺序问题

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3.5 获得队首元素和队尾元素

int myCircularQueueFront(MyCircularQueue* obj)
 {
    if(myCircularQueueIsEmpty(obj))
    return -1;

    return obj->a[obj->head];
}
int myCircularQueueRear(MyCircularQueue* obj)
{
    
    if(myCircularQueueIsEmpty(obj))
    return -1;
    if(obj->back==0)//插入的时候
    return obj->a[obj->size];//表示尾的情况
    else
    return obj->a[obj->back-1];
    //return obj->a[(obj->back-1+obj->size+1)%(obj->size+1)];
}

这里需要注意的是:这里获得队首元素和队尾元素,都需要先判断循环队列是否为空。在获得队尾元素中,一般情况下 obj->a[obj->back-1]是没有问题的,但是如果在插入一个数据,back回到首元素位置上,back-1就会出现问题,会导致越界访问,对此obj->a[(obj->back-1+obj->size+1)%(obj->size+1)]; 可以将这个循环队列展开一段,加obj->size+1再取obj->size+1模,这里同计算循环队列有效数据长度的方式是一样的。

3.6 循环的销毁

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

请添加图片描述

以上就是本篇文章的所有内容,在此感谢大家的观看!这里是店小二初阶数据结构笔记,希望对你在学习初阶数据结构中有所帮助!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Webpack: Loader开发 (1)

概述 如何扩展 Webpack?有两种主流方式,一是 Loader —— 主要负责将资源内容翻译成 Webpack 能够理解、处理的 JavaScript 代码;二是 Plugin —— 深度介入 Webpack 构建过程,重塑 构建逻辑。 相对而言,Loader 的职责…

阶段三:项目开发---搭建项目前后端系统基础架构:任务11:搭建项目后台系统基础架构

任务描述 1、了解搭建民航后端框架 2、使用IDEA创建基于SpringBoot、MyBatis、MySQL、Redis的Java项目 3、以原项目为参照搭建项目所涉及到的各个业务和底层服务 4、以原项目为例,具体介绍各个目录情况并参照创建相关文件夹 任务指导 1、讲框架的选择和原理 …

java信号量(Semaphore)

Java中的信号量(Semaphore)是一种用于控制多个线程对共享资源的访问的同步工具。它可以用来限制可以同时访问某些资源的线程数量。Semaphore 提供了一个计数器来管理许可证的获取和释放,每个许可证代表对资源的一次访问权限。 import java…

DB-GPT-PaperReading

DB-GPT: Empowering Database Interactions with Private Large Language Models 1. 基本介绍 DB-GPT 旨在理解自然语言查询,提供上下文感知响应,并生成高精度的复杂 SQL 查询,使其成为从新手到专家的用户不可或缺的工具。DB-GPT 的核心创新在于其私有 LLM 技术,该技术在…

CIRKD

环境不好满足,不建议复现

CSS【详解】长度单位 ( px,%,em,rem,vw,vh,vmin,vmax,ex,ch )

px 像素 pixel 的缩写,即电子屏幕上的1个点,以分辨率为 1024 * 768 的屏幕为例,即水平方向上有 1024 个点,垂直方向上有 768 个点,则 width:1024px 即表示元素的宽度撑满整个屏幕。 随屏幕分辨率不同,1px …

计网_计算机网络概述

2024.07.03:计算机网络概述 第1节 计算机网络概述 1.1 互连网与互联网1.1.1总结1.1.2 因特网(互联网)发展[自行了解] 1.2 计算机网络组成1.2.1 计算机网络组成方式11.2.2 计算机网络组成方式21.2.3 计算机网络组成方式3 1.3 三种交换方式1.3.1 电路交换(1) 电路交换…

Spring源码十五:Bean的加载

上一篇我们通过Spring源码十四:Spring生命周期介绍了refresh的最后两个方法,至此通过前面大概十篇左右的篇幅介绍完了Spring容器初始化,接下来,将进入Spring另外一个模块Bean相关的知识点。 在Spring框架中,Bean加载过…

人工智能时代打工人摸鱼秘籍(1)- 为啥说大模型像人?

人工智能以势不可挡的方式席卷全球。 所有公司,都在削尖脑袋想,如何在在产品、营销、运营、服务和管理上加持大人工智能的能力。 公司在卷生卷死的时候,有一批人已经偷偷在用大模型提(摸)效(鱼)…

从打印到监测:纳米生物墨水助力3D生物打印与组织监测平台?

从打印到监测:纳米生物墨水助力3D生物打印与组织监测平台? 在 3D 组织工程中,纳米生物墨水是将纳米材料与 ECM 水凝胶结合,以提高其打印性和功能性的重要策略。纳米生物墨水可以增强水凝胶的机械性能、导电性、生物活性&#xff…

2024高考作文题“人工智能”

今年开年到现在,明显的感受就是,咨询人工智能机器人的客户比往年更多了。什么原因,是因为人工成本太高了,今年整体经济环境变差,招不起人,所以想用AI机器人来降低用工成本吗? 还是说因为语音线路…

JVM专题之G1垃圾收集器下

索引(记录)的源码的工作流程图如下: CSet(Collection Set 回收集合) 收集集合(CSet)代表每次GC暂停时回收的一系列目标分区。在任意一次收集暂停中,CSet所有分区都会被释放,内部存活的对象都会被转移到分配的空闲分区中。因此无论是年轻代收集,还是混合收集,工作的机…

PsQuerySystemDllInfo逆向

typedef struct _SYSTEM_DLL_ENTRY {ULONG64 type;UNICODE_STRING FullName;PVOID ImageBase;PWCHAR BaseName;PWCHAR StaticUnicodeBuffer; }SYSTEM_DLL_ENTRY, * PSYSTEM_DLL_ENTRY; 返回值为上面的结构体指针 验证 type: fullname inagebase: pwchar basename PWCHAR …

Spring源码十六:Bean名称转化

在上一篇Spring源码十五:Bean的加载 中我们通过前面的案例方法,找到了Spring真正开始创建Bean的入口,也就是doGetBean方法。该方法是Spring框架中Bean创建与获取的核心逻辑,实现了复杂的Bean生命周期管理。通过单例缓存、合并Bean…

NLP简介

自然语言处理( Natural Language Processing, NLP)是计算机科学领域与人工智能领域中的一个重要方向。它研究能实现人与计算机之间用自然语言进行有效通信的各种理论和方法。自然语言处理是一门融语言学、计算机科学、数学于一体的科学。因此,这一领域的研究将涉及自…

保存在FinalShell服务器登录密码忘记了,如何快速获取到

一、从FinalShell获取服务器基本信息 如图操作会导出一个json文件,可以直接保存在桌面,或者其他位置 json格式如下: {"forwarding_auto_reconnect":false ,"custom_size":false ,"delete_time":0 ,"sec…

从0到1制作单只鳌虾运动轨迹追踪软件

前言 需要准备windows10操作系统,python3.11.9,cuDNN8.9.2.26,CUDA11.8,paddleDetection2.7 流程: 准备数据集-澳洲鳌虾VOC数据集 基于RT-DETR目标检测模型训练导出onnx模型进行python部署平滑滤波处理视频帧保留的…

数字化精益生产系统--QMS质量管理系统

QMS质量管理系统(Quality Management System)是现代企业管理的关键组成部分,旨在确保产品和服务的质量达到或超过客户需求和期望。 以下是对QMS质量管理系统的功能设计:

ip地址突然变了一个城市怎么办

在数字化日益深入的今天,IP地址不仅是网络连接的标识,更是我们网络行为的“身份证”。然而,当您突然发现您的IP地址从一个城市跳转到另一个城市时,这可能会引发一系列的疑问和担忧。本文将带您深入了解IP地址突变的可能原因&#…

软件系统架构的一些常见专业术语

分层架构是逻辑上的,在物理部署上,三层结构可以部署在同一个物理机器上,但是随着网站业务的发展,必然需要对已经分层的模块分离部署,即三层结构分别部署在不同的服务器上,使网站拥有更多的计算资源以应对越…