设计循环队列

目录

设计循环队列

🙂【1】数组循环队列

思路分析

❓1

❓2

❓3

易错总结

创建MyCircularQueue

初始化myCircularQueueCreate

为空否myCircularQueueIsEmpty

为满否myCircularQueueIsFull

插入元素myCircularQueueEnQueue

删除元素myCircularQueueDeQueue

获取首元素myCircularQueueFront

获取尾元素myCircularQueueRear

释放空间myCircularQueueFree

🆗【1】总代码

🙂【2】链表循环队列 

思路分析

易错总结 

创建MyCircularQueue

初始化myCircularQueueCreate

为空否myCircularQueueIsEmpty

为满否myCircularQueueIsFull

插入元素myCircularQueueEnQueue

删除元素myCircularQueueDeQueue

获取首元素myCircularQueueFront

获取尾元素myCircularQueueRear

释放空间myCircularQueueFree

🆗【2】总代码


另外扩展了解一下,实际中我们有时还会使用一种队列叫【循环队列】。如操作系统讲解【生产者消费者模型】时可以就会使用循环队列。环形队列可以使用【数组】实现,也可以使用循环【链表】实现。我们今天来实现一下。

设计循环队列

设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。

循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。

你的实现应该支持如下操作:

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

 

🙂【1】数组循环队列

 

这个【数组循环队列】在逻辑上是如上图所示,但是在物理上,不是循环的。所以特别注意:关于数组循环的这个点,我们必须手动控制。 

思路分析

❓1

空和放一个元素怎么区分?

  • 方法1:back初始化为0,指向队尾元素的下一个位置。
  • 方法2:back初始化为-1,指向队尾元素。 
  • 特别提醒!:用方法1比较好控制

 

❓2

空和满怎样去区分(用方法1区分空和一个元素)?

  • 方法1:设置size。
  • 方法2:malloc多一个空间,不放置元素。(k+1)
  • 以上两者方法都可以。

❓3

怎么处理数组物理上不循环(改成逻辑上循环)?

  • (back+1)%(k+1) = fron
  • obj->back %= obj->k+1
  • return obj->a[(obj->back-1+obj->k+1)%(obj->k+1)]

这里是以判空和满的来讲解,其他的插入和取尾元素是同理的!! 

易错总结

  • 临时变量出了函数就销毁了,必须malloc
  • A%B(A>B对A来说是没有任何影响,A<=B对A来说模去多余的B)---用来处理数组回绕地方
  • 操作符优先级 所以最好都加上括号
  • 处理的表达式的左边不能为计算式(❌obj->front+1%=obj->k+1;)
  • 判空和满直接下标运算即可,不用用数组(为什么不能用数组❓)
  • 释放空间先释放数组空间,在释放myCircularQueue

创建MyCircularQueue

//用数组实现+多开辟一个空间不放元素
typedef struct {int*a;int front;int back;//数组下标int k;//循环队列的最多放置数据
} MyCircularQueue;

初始化myCircularQueueCreate

MyCircularQueue* myCircularQueueCreate(int k) {MyCircularQueue*obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));int*tmp=(int*)malloc(sizeof(int)*(k+1));//多开辟一个空间obj->a=tmp;obj->front=0;obj->back=0;//指向最后一个元素的下一个obj->k=k;return obj;
}

为空否myCircularQueueIsEmpty

//判断循环队列是否为空
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {return obj->front == obj->back;//==0 
}

为满否myCircularQueueIsFull

//判断是否为满
bool myCircularQueueIsFull(MyCircularQueue* obj) {return (obj->back+1) % (obj->k+1) == obj->front;//back+1=front//操作符优先级问题
}

插入元素myCircularQueueEnQueue

 考虑下这个特殊情况!

//插入元素
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {if(myCircularQueueIsFull(obj))//true 满了{return false;}obj->a[obj->back] = value;obj->back++;obj->back %= obj->k+1;//处理//obj->front+1%=obj->k+1;//处理左边不能为计算表达式return true;
}

删除元素myCircularQueueDeQueue

  考虑下这个特殊情况!

//删除元素
bool myCircularQueueDeQueue(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj)){return false;}else{obj->front++;obj->front%=obj->k+1;//处理return true;}
}

获取首元素myCircularQueueFront

//获取首元素
int myCircularQueueFront(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj)){return -1;}elsereturn obj->a[obj->front];
}

获取尾元素myCircularQueueRear

  考虑下这个特殊情况!

//获取尾元素
int myCircularQueueRear(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj)){return -1;}else//return obj->a[(obj->back-1+obj->k+1)%(obj->k+1)];return obj->a[(obj->back+obj->k)%(obj->k+1)];
}

释放空间myCircularQueueFree

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

🆗【1】总代码

//用数组实现+多开辟一个空间不放元素
typedef struct {int*a;int front;int back;//数组下标int k;//循环队列的最多放置数据
} MyCircularQueue;MyCircularQueue* myCircularQueueCreate(int k) {MyCircularQueue*obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));int*tmp=(int*)malloc(sizeof(int)*(k+1));//多开辟一个空间obj->a=tmp;obj->front=0;obj->back=0;//指向最后一个元素的下一个obj->k=k;return obj;
}
//判断循环队列是否为空
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {return obj->front == obj->back;//==0 
}//判断是否为满
bool myCircularQueueIsFull(MyCircularQueue* obj) {return (obj->back+1) % (obj->k+1) == obj->front;//back+1=front//操作符优先级问题
}//插入元素
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {if(myCircularQueueIsFull(obj))//true 满了{return false;}obj->a[obj->back] = value;obj->back++;obj->back %= obj->k+1;//处理//obj->front+1%=obj->k+1;//处理左边不能为计算表达式return true;
}//删除元素
bool myCircularQueueDeQueue(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj)){return false;}else{obj->front++;obj->front%=obj->k+1;//处理return true;}
}//获取首元素
int myCircularQueueFront(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj)){return -1;}elsereturn obj->a[obj->front];
}//获取尾元素
int myCircularQueueRear(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj)){return -1;}else//return obj->a[(obj->back-1+obj->k+1)%(obj->k+1)];return obj->a[(obj->back+obj->k)%(obj->k+1)];
}//释放空间
void myCircularQueueFree(MyCircularQueue* obj) {free(obj->a);free(obj);obj=NULL;
}

🙂【2】链表循环队列 

链表很简单对于处理循环的问题,只要实现单项循环链表即可。这里的难点就是:(1)创建单项循环链表。(2)找到back的前一个元素

思路分析

关于判【空/一个元素】& 判【空/满】都是和上面数组是一样的。这里不过多阐述。

怎么去找到back的前一个元素?

其实这个问题在我们前面博文实现链表也详细讲解,相信大家可以轻松掌握!!

        Node*prev=obj->front;while(prev->next != obj->back){prev=prev->next;}

易错总结 

  • 初始化一定要把back置回开头
  • 找back前一个元素:要么用三个指针,要么遍历一遍链表。
  • 释放空间不能遍历去释放,会造成野指针。
  • 释放空间先把循环链表改变成单向链表,才能循环遍历释放。 

创建MyCircularQueue

typedef struct Node
{int val;struct Node*next;
}Node;//节点typedef struct {Node*front;Node*back;    int size;//计算放入队列的元素个数
} MyCircularQueue;//循环队列

初始化myCircularQueueCreate

MyCircularQueue* myCircularQueueCreate(int k) {MyCircularQueue*obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));obj->front=NULL;obj->back=NULL;while(k--){Node*newnode=(Node*)malloc(sizeof(Node));if(obj->front == NULL){obj->front=obj->back=newnode;obj->front->val=0;}else{obj->back->next=newnode;obj->back=newnode;obj->back->val=0;}}//循环obj->back->next=obj->front;//backobj->back=obj->front;//obj->size=0;return obj;
}

为空否myCircularQueueIsEmpty

//判断循环队列是否为空
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {if(obj->size == 0 && obj->front == obj->back)return true;elsereturn false;
}

为满否myCircularQueueIsFull

//判断是否为满
bool myCircularQueueIsFull(MyCircularQueue* obj) {if(obj->size != 0 && obj->front == obj->back)return true;elsereturn false;
}

插入元素myCircularQueueEnQueue

//插入元素
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {if(myCircularQueueIsFull(obj))//true 满了{return false;}else{obj->back->val=value;obj->back=obj->back->next;obj->size++;return true;}
}

删除元素myCircularQueueDeQueue

//删除元素
bool myCircularQueueDeQueue(MyCircularQueue* obj)
{if(myCircularQueueIsEmpty(obj)){return false;}else{obj->front=obj->front->next;//❌易错obj->size--;return true;}
}

获取首元素myCircularQueueFront

//获取首元素
int myCircularQueueFront(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj)){return -1;}return obj->front->val;
}

获取尾元素myCircularQueueRear

//获取尾元素
int myCircularQueueRear(MyCircularQueue* obj) 
{if(myCircularQueueIsEmpty(obj)){return -1;}//❌易错else{Node*prev=obj->front;while(prev->next != obj->back){prev=prev->next;}return prev->val;}
}

释放空间myCircularQueueFree

//释放空间
//❌易错
void myCircularQueueFree(MyCircularQueue* obj) {Node*prev=obj->front;while(prev->next != obj->front){prev=prev->next;}//prev是最后一个prev->next=NULL;//while(obj->front->next != NULL){Node*tmp=obj->front;obj->front=obj->front->next;free(tmp);tmp=NULL;}free(obj->front);obj->front=NULL;free(obj);obj=NULL;
}

🆗【2】总代码

typedef struct Node
{int val;struct Node*next;
}Node;//节点typedef struct {Node*front;Node*back;    int size;//计算放入队列的元素个数
} MyCircularQueue;//循环队列MyCircularQueue* myCircularQueueCreate(int k) {MyCircularQueue*obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));obj->front=NULL;obj->back=NULL;while(k--){Node*newnode=(Node*)malloc(sizeof(Node));if(obj->front == NULL){obj->front=obj->back=newnode;obj->front->val=0;}else{obj->back->next=newnode;obj->back=newnode;obj->back->val=0;}}//循环obj->back->next=obj->front;//backobj->back=obj->front;//obj->size=0;return obj;
}//判断循环队列是否为空
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {if(obj->size == 0 && obj->front == obj->back)return true;elsereturn false;
}//判断是否为满
bool myCircularQueueIsFull(MyCircularQueue* obj) {if(obj->size != 0 && obj->front == obj->back)return true;elsereturn false;
}//插入元素
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {if(myCircularQueueIsFull(obj))//true 满了{return false;}else{obj->back->val=value;obj->back=obj->back->next;obj->size++;return true;}
}//删除元素
bool myCircularQueueDeQueue(MyCircularQueue* obj)
{if(myCircularQueueIsEmpty(obj)){return false;}else{obj->front=obj->front->next;obj->size--;return true;}
}//获取首元素
int myCircularQueueFront(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj)){return -1;}return obj->front->val;
}//获取尾元素
int myCircularQueueRear(MyCircularQueue* obj) 
{if(myCircularQueueIsEmpty(obj)){return -1;}else{Node*prev=obj->front;while(prev->next != obj->back){prev=prev->next;}return prev->val;}
}//释放空间
void myCircularQueueFree(MyCircularQueue* obj) {Node*prev=obj->front;while(prev->next != obj->front){prev=prev->next;}//prev是最后一个prev->next=NULL;//while(obj->front->next != NULL){Node*tmp=obj->front;obj->front=obj->front->next;free(tmp);tmp=NULL;}free(obj->front);obj->front=NULL;free(obj);obj=NULL;
}

 还有数据结构的【栈】和操作系统的【栈】是不一样的。数据结构的【栈】是一种线性表。操作系统的【栈】是内存的区域,会发生栈溢出和内存泄露的问题(递归程序/返回条件有问题),但是数据结构【栈】不会。

✔✔✔✔✔最后,感谢大家的阅读,若有错误和不足,欢迎指正!

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

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

相关文章

【香橙派】实战记录2——烧录安卓镜像及基本功能

文章目录 一、安卓烧录二、安卓基本功能1、蓝牙2、相机功能3、投屏 一、安卓烧录 检查环境&#xff1a;检查PC系统&#xff0c;确保有Microsoft Visual C 2008 Redistrbutable - x86&#xff0c;否则在官网下载的官方工具 - 安卓镜像烧录工具里运行vcredist_x86.exe。 插入存储…

吸烟引发火灾,两涉案人被刑事拘留,是时候让AI保卫我们的安全了

3月23日17时30分&#xff0c;招远市玲珑镇睦邻庄村北山森林失火。经查&#xff0c;系王某某在山林作业期间&#xff0c;吸烟引发山火造成重大损失。王某某因涉嫌失火罪已被招远市公安局刑事拘留。 3月28日14时04分&#xff0c;龙口市下丁家镇大庄村南部山域森林失火。经查&…

PCB布线为什么不能走直角或锐角-笔记

PCB布线为什么不能走直角或锐角-笔记 摘要一.PCB走线在直角转弯的地方&#xff0c;信号前后部分相互影响这几个理由我们来一一分析一下传输线的直角带来的寄生电容从阻抗的角度来看直角的尖角产生放电或者电磁辐射走线直角的工艺问题 摘要 有一定熟悉画过PCB板的人或者PCB教学…

C 中的结构 - 存储、指针、函数和自引用结构

0. 结构体的内存分配 当声明某种类型的结构变量时&#xff0c;结构成员被分配连续&#xff08;相邻&#xff09;的内存位置。 struct student{char name[20];int roll;char gender;int marks[5];} stu1; 此处&#xff0c;内存将分配给name[20]、roll、gender和marks[5]。st1这…

Python--使用布林线设计均值回归策略

在本教程中,我们将探讨均值回归的概念以及如何使用 Python 中的布林线设计交易策略。均值回归是一种流行的交易策略,它基于这样的假设:随着时间的推移,资产价格往往会恢复到历史平均水平。布林线 (Bollinger Bands) 由约翰布林格 (John Bollinger) 开发,是一种技术分析工具…

分类预测 | Matlab实现NGO-KELM北方苍鹰算法优化核极限学习机分类预测

分类预测 | Matlab实现NGO-KELM北方苍鹰算法优化核极限学习机分类预测 目录 分类预测 | Matlab实现NGO-KELM北方苍鹰算法优化核极限学习机分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现NGO-KELM北方苍鹰算法优化核极限学习机分类预测&#xff08;完…

深度学习(一):Pytorch之YOLOv8目标检测

1.YOLOv8 2.模型详解 2.1模型结构设计 和YOLOv5对比&#xff1a; 主要的模块&#xff1a; ConvSPPFBottleneckConcatUpsampleC2f Backbone ----->Neck------>head Backdone 1.第一个卷积层的 kernel 从 6x6 变成了 3x3 2. 所有的 C3 模块换成 C2f&#xff0c;可以发现…

大模型下交互式数据挖掘的探索与发现

在这个数据驱动的时代&#xff0c;数据挖掘已成为解锁信息宝库的关键。过去&#xff0c;我们依赖传统的拖拉拽方式来建模&#xff0c;这种方式在早期的数据探索中起到了作用&#xff0c;但随着数据量的激增和需求的多样化&#xff0c;它的局限性逐渐显露。 >>>> 首…

IPtables防火墙详解

一、IPtables介绍 iptables是unix/linux自带的一款开放源代码的完全自由的基于包过滤(对OSI模型的四层或者是四层以下进行过滤)的防火墙工具&#xff0c;它的功能十分强大&#xff0c;使用非常灵活&#xff0c;可以对流入和流出服务器的数据包进行很精细的控制。主要针对网络访…

微软发布了Orca 2,一对小型语言模型,它们的性能超越了体积更大的同类产品

尽管全球目睹了OpenAI的权力斗争和大规模辞职&#xff0c;但作为AI领域的长期支持者&#xff0c;微软并没有放慢自己的人工智能努力。今天&#xff0c;由萨提亚纳德拉领导的公司研究部门发布了Orca 2&#xff0c;这是一对小型语言模型&#xff0c;它们在零样本设置下对复杂推理…

[Docker]十一.Docker Swarm集群raft算法,Docker Swarm Web管理工具

一.Docker Swarm集群raft算法讲解 Raft &#xff1a;一致性算法&#xff0c;在保证大多数管理节点存活的情况下&#xff0c;集群才能使用&#xff0c; 所以就要求如果集群的话&#xff0c; manager 节点必须 >3 台 &#xff0c;如果是两个台&#xff0c;其中一台宕机&#…

分享几种 Java8 中通过 Stream 对列表进行去重的方法

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 1. Stream 的 distinct…

pgz easyexcel如何给excel文件添加自定义属性

免费API方式 直接上传URL,自定义修改Excel 视频演示【内含接口地址】 https://www.ixigua.com/7304510132812153385 前情提示 | 功能说明 多选仅支持微软office、office365系列Excel。因为WPS宏功能需要企业版且付费生成xlsx、xlsm等文件,office和WPS均可以打开,均可以单…

数据结构---堆

1.堆的概念及结构 堆的性质&#xff1a; 堆中某个节点的值总是不大于或不小于其父节点的值堆总是一棵完全二叉树 2.举例说明 堆一般是把数组数据看做是一棵完全二叉树 小堆要求&#xff1a;任意一个父亲<孩子大堆要求&#xff1a;任意一个父亲>孩子 比如&#xff1…

【超详细】vue项目:Tinymce富文本使用教程以及踩坑总结+功能扩展

【【超详细】vue项目&#xff1a;Tinymce富文本使用教程以及踩坑总结功能扩展 引言&#xff1a;一、 开始二、快速开始1、安装Tinymce 三、封装成Vue组件1、文件结构2、index.vue3、dynamicLoadScript.js4、plugin.js5、toolbar.js 四、使用Tinymce组件五、业务逻辑实现1、添加…

【UE5】五大基类及其使用

UObject UObject表示对象&#xff0c;准确来说&#xff0c;虚幻引擎中的对象基础类为UObject UObject提供了以下功能&#xff1a; 垃圾收集&#xff08;Garbage collection&#xff09;引用自动更新&#xff08;Reference updating&#xff09;反射&#xff08;Reflection&am…

亚马逊云与生成式 AI 的融合——生成式AI的应用领域

文章目录 前言亚马逊云科技增强客户体验聊天机器人和虚拟助手亚马逊云科技 鸿翼&#xff1a;提供精准检索和问答&#xff0c;显著提升全球化售后服务体验AI 赋能的联络中心智能导购&个性化推荐智慧数字人 提升员工生成力和创造力对话式搜索亚马逊云科技 西门子&#xff1…

Vue3 Router跳转传参

最近遇到这个问题router跳转传参&#xff0c;真是要了老命了。 根据网上各位大神给出的方法&#xff0c;试了 import { useRouter } from vue-routerconst router useRouter()//1. 无法跳转 router.push(name:,params:{})//2. 可以跳转, 但需要在定义router同时定义占位符&a…

Redis7--基础篇4(Redis事务)

Redis事务是什么 可以一次执行多个命令&#xff0c;本质是一组命令的集合&#xff0c;一个事务中的所有命令都会序列化&#xff0c;按顺序串行&#xff0c;而不会被其他命令插入。 其作用就是在一个队列中&#xff0c;一次性、顺序、排他的执行一系列命令。 Redis事务 VS 数据…

使用gparted进行ubuntu虚拟机的磁盘扩容(解决gparted无法拖动分区的问题)

在学习内核编译下载linux内核源码的时候&#xff0c;由于源码非常大&#xff0c;下载的时候提示磁盘空间不足&#xff0c;我才意识到刚开始创建虚拟机的时候分配了20GB的空间现在已经快用光了。在VM的设置里可以进行扩容&#xff0c;我扩展到了30GB重启却发现空间并没有加到我使…