设计循环队列

目录

设计循环队列

🙂【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.mzph.cn/news/184701.shtml

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

相关文章

load_policy命令详解与实例

1. 概述 load_policy是一个与systemd相关的命令,用于加载SELinux(Security-Enhanced Linux)策略。load_policy命令通常与SELinux策略文件(通常是以.pp或.te为扩展名的文件)一起使用,用于加载新的或更新的SELinux策略。 在加载新的SELinux策略后,新的访问控制规则将生效…

无醇啤酒行业分析:预计2028年将达到106亿美元

按照国际惯用的标准划分&#xff0c;通常将酒精度3.5%-4%的称为普通啤酒&#xff0c;将酒精度大于0.5%、小于2.5%的称为低醇啤酒&#xff0c;而酒精度小于0.5%便称为无醇啤酒。酒精给人带来的兴奋感&#xff0c;与体育比赛的紧张刺激相辅相成&#xff0c;啤酒也成为了许多球迷们…

基于UDP的网络聊天室

客户端 #include <myhead.h> //定义存储信息结构体 typedef struct _MSG {char code; //操作码&#xff1a;L表示登录C表示群聊S表示系统消息S表示退出char name[128]; char txt[256];}msg_t;//定义保存客户端网络信息的链表 typedef struct _ADDR {struct sockaddr_i…

第十四章 算法和数据结构

Python基础、函数、模块、面向对象、网络和并发编程、数据库和缓存、 前端、django、Flask、tornado、api、git、爬虫、算法和数据结构、Linux、设计题、客观题、其他 第十四章 算法和数据结构 1. 顺序表、链表的区别及应用场景。 顺序表&#xff08;Sequential List&#xf…

【elementUI】el-tab相关问题

Tabs 标签页 分隔内容上有关联但属于不同类别的数据集合。 <template><el-tabs v-model"activeName" tab-click"handleClick"><el-tab-pane label"用户管理" name"first">用户管理</el-tab-pane><el-tab-p…

Linux重置MySql密码(简洁版)

关闭验证 /etc/my.cnf-->[mysqld]-->skip-grant-tables 重启MySql service mysql restart 登陆MySql mysql -u root 刷新权限 FLUSH PRIVILEGES; 更新密码 ALTER USER rootlocalhost IDENTIFIED BY 123456; 退出MySql exit 打开验证 /etc/my.cnf-->[mysqld]-->skip…

建设“参与城市”大学--SMU在2023年绿色金融全球论坛上分享观点

2023年11月21日&#xff0c;由新加坡管理大学&#xff08;SMU&#xff0c;简称新大&#xff09;和中国人民大学&#xff08;RUC&#xff0c;简称人大&#xff09;联合主办的“绿色金融与治理&#xff1a;从承诺到行动”全球论坛在北京召开。论坛汇集了来自新加坡、中国及世界各…

数据类型及强制转换

数据类型范围&#xff08;基本&#xff09; 数据类型占内存字节数表示范围数量级char&#xff08;signed char&#xff09;1-128~1272unsigned char10~2552short int&#xff08;signed short int&#xff09;2-32,768~32,7674unsigned short int20~65,5354int&#xff08;sig…

ThreeJs样例 webgl_shadow_contact 分析

webgl_shadow_contact 官方样例中&#xff0c;对阴影的渲染比较特殊&#xff0c;很值得借鉴&#xff0c;学习渲染阴影的思路&#xff1b;这个例子中对阴影的渲染&#xff0c;并没有使用任何光源&#xff0c;没有用shadowmap的常规方式 渲染阴影&#xff1b;而是使用了深度材质T…

SpringBoot项目打成jar包后,上传的静态资源(图片等)如何存储和访问

1.问题描述&#xff1a; 使用springboot开发一个项目&#xff0c;开发文件上传的时候&#xff0c;通常会将上传的文件存储到资源目录下的static里面&#xff0c;然后在本地测试上传文件功能没有问题&#xff0c;但是将项目打成jar包放到服务器上运行的时候就会报错&#xff0c…

Comodo SSL证书适合电商企业使用吗?

在电子商务领域&#xff0c;保护用户的个人和财务信息是至关重要的。SSL证书作为一项重要的安全工具&#xff0c;可以为电商企业提供信任和保护。Comodo SSL证书作为市场上的一家知名的证书颁发机构&#xff0c;是否适合电商企业使用呢&#xff1f;本文将探讨这个问题。 1、可信…

深入理解什么是消息队列

一、什么是消息队列 消息&#xff08;Message&#xff09;是指在应用之间传送的数据&#xff0c;消息可以非常简单&#xff0c;比如只包含文本字符串&#xff0c;也可以更复杂&#xff0c;可能包含嵌入对象。 消息队列&#xff08;Message Queue&#xff09;是一种应用间的通信…

P26 C++创建并初始化对象

目录 前言 01 在堆栈上创建对象 02 堆栈上创建对象有什么区别 03 在栈上实例化对象 04 在堆中实例化对象 前言 本章我们讨论一下 C 创建对象的相关问题。 如果你还不了解什么是类&#xff0c;可以点击下文查看 P9 C类-CSDN博客 本章以下主要讲解以下几点 在栈上创建对象…

大数据分析与应用实验任务十

大数据分析与应用实验任务十 实验目的&#xff1a; 通过实验掌握spark SQL的基本编程方法&#xff1b; 熟悉RDD到DataFrame的转化方法&#xff1b; 通过实验熟悉spark SQL管理不同数据源的方法。 实验任务&#xff1a; 进入pyspark实验环境&#xff0c;在桌面环境打开jup…

Linux:docker镜像的创建(5)

1.基于已有镜像创建 步骤&#xff1a; 1.将原始镜像加入容器并运行 2.在原始镜像中部署各种服务 3.退出容器 4.使用下面命令将容器生成新的镜像 现在我们在这个容器里做了一些配置&#xff0c;我们要把他做成自己镜像 docker commit -m "centos7_123" -a "tarr…

20. Matplotlib 数据可视化

目录 1. 简介2. Matplotlib 开发环境2.1 画图2.2 画图接口2.4 线形图2.5 散点图2.6 等高线图2.7 直方图 1. 简介 Matplotlib网址&#xff1a;https://matplotlib.org/ 数据可视化是数据分析中最重要的工作之一。Matploblib是建立在Numpy数组基础上的多平台数据可视化程序库&a…

PostgreSQL 分区表插入数据及报错:子表明明存在却报不存在以及column “xxx“ does not exist 解决方法

PostgreSQL 分区表插入数据及报错&#xff1a;子表明明存在却报不存在以及column “xxx“ does not exist 解决方法 问题1. 分区表需要先创建子表在插入&#xff0c;创建子表立马插入后可能会报错子表不存在&#xff1b;解决&#xff1a; 创建子表及索引后&#xff0c;sleep10毫…

【JavaWeb】会话过滤器监听器

会话&过滤器&监听器 文章目录 会话&过滤器&监听器一、会话1.1 Cookie1.2 Session1.3 三大域对象 二、过滤器三、监听器3.1 application域监听器3.2 session域监听器3.3 request域监听器3.4 session域的两个特殊监听器3.4.1 session绑定监听器3.4.2 钝化活化监听…

医院电子病历编辑器源码(支持云端SaaS服务)

电子病历系统基于云端SaaS服务的方式&#xff0c;采用B/S&#xff08;Browser/Server&#xff09;架构提供&#xff0c;采用前后端分离模式开发和部署。使用用户通过浏览器即能访问&#xff0c;无需关注系统的部署、维护、升级等问题&#xff0c;系统充分考虑了模板化、 配置化…

k8s有状态部署mysql主从(local pv持久化)

1、修改自己对应的命名空间 2、local pv的方式必须先创建好目录在给权限 3、sts部署文件密码都要修改好在部署 yaml资源文件如下&#xff1a; #配置mysql的root密码再部署&#xff0c;如果部署了在修改root密码就会失败&#xff0c;必须在初始化就把root密码修改好 #部署采…