数据结构:循环队列的实现(leetcode622.设计循环队列)
目录
一.循环队列简单介绍
二.用静态数组实现循环队列
1.数组循环队列结构设计
2.数组循环队列的堆区内存申请接口
3.数据出队和入队的接口实现
4.其他操作接口
5.数组循环队列的实现代码总览
三.静态单向循环链表实现循环队列
1.链表循环队列的结构设计
2.创建静态单向循环链表的接口
3.数据的出队和入队接口
4.其他队列操作接口
5.静态链表循环队列总体代码
问题来源:622. 设计循环队列 - 力扣(Leetcode)
一.循环队列简单介绍
- 循环队列一般是一种静态的线性数据结构,其中的数据符合先进先出的原则.
- 循环队列的容器首地址和容器尾地址通过特定操作(比如指针链接,数组下标取余等方式)相连通,从而实现了容器空间的重复利用(在一个非循环静态队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间)
![]()
二.用静态数组实现循环队列
维护队列的结构体:
typedef struct {int * arry; //指向堆区数组的指针int head; //队头指针int tail; //队尾指针(指向队尾数据的下一个位置)(不指向有效数据)int capacity;//静态队列的容量 } MyCircularQueue;
1.数组循环队列结构设计
我们假定静态数组的容量为k(可存储k个数据):
- 根据队列的基本数据结构:有两个指针用于维护数组中的有效数据空间,分别为head指针和tail指针,head指针用于指向队头数据,tail用于指向队尾数据的下一个位置(即tail指针不指向有效数据)
- 如图所示,head指针和tail指针之间就是有效数据的内存空间
- 通过head指针和tail指针的关系来实现队列的判满(判断队列空间是否已被占满)与判空(判断队列是否为空队列);为了达到这个目的,我们需要将静态数组的容量大小设置为k+1(即多设置一个元素空间)
- 队列的判空条件: tail == head;
- 队列的判满条件: (tail+1)%(k+1) == head;
另外一种情形:
- 由此我们可以先设计出队列的判满和判空接口:
bool myCircularQueueIsEmpty(MyCircularQueue* obj) //判断队列是否为空 {assert(obj);return (obj->tail == obj->head); }bool myCircularQueueIsFull(MyCircularQueue* obj) //判断队列是否为满 {assert(obj);return ((obj->tail+1)%(obj->capacity +1) == obj->head); }
2.数组循环队列的堆区内存申请接口
- 在堆区上创建MyCircularQueue结构体,同时为队列申请一个空间大小为(k+1)*sizeof(DataType)字节的数组:
MyCircularQueue* myCircularQueueCreate(int k) //k个容量大小的循环队列的初始化接口 {MyCircularQueue * tem = (MyCircularQueue *)malloc(sizeof(MyCircularQueue));//开辟维护循环队列的结构体if(NULL == tem){perror("malloc failed");exit(-1);}tem->arry = NULL;tem->capacity = k; //队列的数据容量为ktem->arry = (int*)malloc((k+1)*sizeof(int));//开辟堆区数组if(NULL == tem->arry){perror("malloc failed");exit(-1);}//将head,tail下标初始化为0tem->head = 0; tem->tail = 0;return tem; }
3.数据出队和入队的接口实现
数据出队和入队的图解:
![]()
- 根据图解我们可以设计出数据入队和出队的接口:
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) //数据入队接口 {assert(obj);if(myCircularQueueIsFull(obj)){return false;}//确保队列没满obj->arry[obj->tail]=value;obj->tail = (obj->tail + 1)%(obj->capacity +1);return true; }bool myCircularQueueDeQueue(MyCircularQueue* obj) //数据出队接口 {assert(obj);if(myCircularQueueIsEmpty(obj)){return false;}//确保队列不为空obj->head = (obj->head +1)%(obj->capacity +1);return true; }
4.其他操作接口
返回队头数据的接口:
int myCircularQueueFront(MyCircularQueue* obj) //返回队头数据的接口 {assert(obj);if(myCircularQueueIsEmpty(obj)){return -1;}return obj->arry[obj->head]; }返回队尾数据的接口:
int myCircularQueueRear(MyCircularQueue* obj) //返回队尾数据的接口 {assert(obj);if(myCircularQueueIsEmpty(obj)){return -1;}int labelret = ((obj->tail-1)>=0)? obj->tail-1 : obj->capacity;//注意tail如果指向数组首地址,则尾数据位于数组最后一个位置return obj->arry[labelret]; }队列的销毁接口:
void myCircularQueueFree(MyCircularQueue* obj) //销毁队列的接口 {assert(obj);free(obj->arry);obj->arry = NULL;free(obj);obj = NULL; }
5.数组循环队列的实现代码总览
数组循环队列总体代码:
typedef struct {int * arry; //指向堆区数组的指针int head; //队头指针int tail; //队尾指针(指向队尾数据的下一个位置)(不指向有效数据)int capacity;//静态队列容量 } MyCircularQueue;bool myCircularQueueIsEmpty(MyCircularQueue* obj); bool myCircularQueueIsFull(MyCircularQueue* obj); //顺序编译注意:先被使用而后被定义的函数要记得进行声明MyCircularQueue* myCircularQueueCreate(int k) //循环队列初始化接口 {MyCircularQueue * tem = (MyCircularQueue *)malloc(sizeof(MyCircularQueue));//开辟维护循环队列的结构体if(NULL == tem){perror("malloc failed");exit(-1);}tem->arry = NULL;tem->capacity = k; //队列的数据容量为ktem->arry = (int*)malloc((k+1)*sizeof(int));//开辟堆区数组if(NULL == tem->arry){perror("malloc failed");exit(-1);}tem->head = 0;tem->tail = 0;return tem; }bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) //数据入队接口 {assert(obj);if(myCircularQueueIsFull(obj)){return false;}//确保队列没满obj->arry[obj->tail]=value;obj->tail = (obj->tail + 1)%(obj->capacity +1);return true; }bool myCircularQueueDeQueue(MyCircularQueue* obj) //数据出队接口 {assert(obj);if(myCircularQueueIsEmpty(obj)){return false;}//确保队列不为空obj->head = (obj->head +1)%(obj->capacity +1);return true; }int myCircularQueueFront(MyCircularQueue* obj) //返回队头数据的接口 {assert(obj);if(myCircularQueueIsEmpty(obj)){return -1;}return obj->arry[obj->head]; }int myCircularQueueRear(MyCircularQueue* obj) //返回队尾数据的接口 {assert(obj);if(myCircularQueueIsEmpty(obj)){return -1;}int labelret = ((obj->tail-1)>=0)? obj->tail-1 : obj->capacity;//注意tail如果指向数组首地址,则尾数据位于数组最后一个位置return obj->arry[labelret]; }bool myCircularQueueIsEmpty(MyCircularQueue* obj) //判断队列是否为空 {assert(obj);return (obj->tail == obj->head); }bool myCircularQueueIsFull(MyCircularQueue* obj) //判断队列是否为满 {assert(obj);return ((obj->tail+1)%(obj->capacity +1) == obj->head); }void myCircularQueueFree(MyCircularQueue* obj) //销毁队列的接口 {assert(obj);free(obj->arry);obj->arry = NULL;free(obj);obj = NULL; }力扣题解测试:
三.静态单向循环链表实现循环队列
链表节点结构体定义:
typedef struct listnode {int data;struct listnode * next; }ListNode;维护链表循环队列的结构体:
typedef struct {int capacity; //记录队列容量大小ListNode * head; //指向队头节点ListNode * tail; //指向队尾节点 } MyCircularQueue;
1.链表循环队列的结构设计
静态单向循环链表的容量大小为k:
- 与数组循环队列类似,我们同样需要开辟一个节点个数为k+1的静态循环链表
- 链表循环队列的总体结构图示:
另外一种队列判满的情形:
- 链表循环队列的判满条件(判断队列空间是否被占满的关系式):tail->next == head;
- 链表循环队列的判空条件(判断队列是否为空队列的关系式): tail == head;
链表循环队列的判满和判空的接口:
bool myCircularQueueIsEmpty(MyCircularQueue* obj) //判断队列是否为空 {assert(obj);return(obj->head == obj->tail); }bool myCircularQueueIsFull(MyCircularQueue* obj) //判断队列是否为满 {assert(obj);return (obj->tail->next == obj->head); }
2.创建静态单向循环链表的接口
实现一个接口,创建一个维护链表循环队列的结构体同时创建容量大小为k+1的静态单向循环链表:
MyCircularQueue* myCircularQueueCreate(int k) //循环队列初始化接口 {int NodeNum =k+1; //创建k+1个链表节点MyCircularQueue* object = (MyCircularQueue *)malloc(sizeof(MyCircularQueue));assert(object); //申请维护循环队列的结构体object->capacity = k;ListNode * preNode = NULL; //用于记录前一个链接节点的地址while(NodeNum){if(NodeNum == k+1){ ListNode * tem = (ListNode *)malloc(sizeof(ListNode));assert(tem);preNode = tem;object->tail = object->head=tem; //让tail和head指向同一个初始节点}else{ListNode * tem = (ListNode *)malloc(sizeof(ListNode));assert(tem);preNode->next = tem; //链接链表节点preNode = tem;}NodeNum--;}preNode->next = object->head; //将表尾与表头相接return object; }
3.数据的出队和入队接口
数据出入队图解:
根据图解实现数据出入队接口:
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)//数据入队接口(从队尾入队) {assert(obj);if(!obj || myCircularQueueIsFull(obj)) //确定队列没满{return false;} obj->tail->data = value; //数据入队obj->tail = obj->tail->next;return true; }bool myCircularQueueDeQueue(MyCircularQueue* obj) //数据出队接口 {assert(obj);if(!obj || myCircularQueueIsEmpty(obj)){return false;}//数据出队obj->head = obj->head->next;return true; }
4.其他队列操作接口
返回队头数据的接口:
int myCircularQueueFront(MyCircularQueue* obj) //返回队头数据的接口 {assert(obj);if(myCircularQueueIsEmpty(obj)){return -1;}return obj->head->data; //返回队头元素 }返回队尾数据的接口:
int myCircularQueueRear(MyCircularQueue* obj) //返回队尾数据的接口 {assert(obj);if(myCircularQueueIsEmpty(obj)){return -1;}ListNode * tem = obj->head;while(tem->next != obj->tail) //寻找队尾元素{tem=tem->next;}return tem->data; //返回队尾元素 }队列销毁接口:
队列销毁过程图解:
void myCircularQueueFree(MyCircularQueue* obj) //销毁队列的接口 {assert(obj);//利用头指针来完成链表节点的释放ListNode * endpoint = obj->head; //记录一个节点释放的终点obj->head = obj->head->next;while(obj->head!=endpoint){ListNode * tem = obj->head->next;free(obj->head);obj->head = tem;}free(endpoint); //释放掉终点节点free(obj); //释放掉维护环形队列的结构体 }
5.静态链表循环队列总体代码
总体代码:
typedef struct listnode {int data;struct listnode * next; }ListNode;typedef struct {int capacity;ListNode * head;ListNode * tail;int taildata; //单向链表找尾复杂度为O(N),因此我们用一个变量来记录队尾数据 } MyCircularQueue;bool myCircularQueueIsEmpty(MyCircularQueue* obj); bool myCircularQueueIsFull(MyCircularQueue* obj); //顺序编译注意:先被使用而后被定义的函数要记得进行声明MyCircularQueue* myCircularQueueCreate(int k) //循环队列初始化接口 {int NodeNum =k+1; //创建k+1个链表节点MyCircularQueue* object = (MyCircularQueue *)malloc(sizeof(MyCircularQueue));assert(object); //申请维护循环队列的结构体object->capacity = k;ListNode * preNode = NULL; //用于记录前一个链接节点的地址while(NodeNum){if(NodeNum == k+1){ ListNode * tem = (ListNode *)malloc(sizeof(ListNode));assert(tem);preNode = tem;object->tail = object->head=tem; //让tail和head指向同一个初始节点}else{ListNode * tem = (ListNode *)malloc(sizeof(ListNode));assert(tem);preNode->next = tem; //链接链表节点preNode = tem;}NodeNum--;}preNode->next = object->head; //将表尾与表头相接return object; }bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) //数据入队接口(从队尾入队) {assert(obj);if(!obj || myCircularQueueIsFull(obj)) //确定队列没满{return false;} obj->tail->data = value; //数据入队obj->tail = obj->tail->next;return true; }bool myCircularQueueDeQueue(MyCircularQueue* obj) //数据出队接口 {assert(obj);if(!obj || myCircularQueueIsEmpty(obj)){return false;}obj->head = obj->head->next;return true; }int myCircularQueueFront(MyCircularQueue* obj) //返回队头数据的接口 {assert(obj);if(myCircularQueueIsEmpty(obj)){return -1;}return obj->head->data; }int myCircularQueueRear(MyCircularQueue* obj) //返回队尾数据的接口 {assert(obj);if(myCircularQueueIsEmpty(obj)){return -1;}ListNode * tem = obj->head;while(tem->next != obj->tail) //寻找队尾元素{tem=tem->next;}return tem->data; }bool myCircularQueueIsEmpty(MyCircularQueue* obj) //判断队列是否为空 {assert(obj);return(obj->head == obj->tail); }bool myCircularQueueIsFull(MyCircularQueue* obj) //判断队列是否为满 {assert(obj);return (obj->tail->next == obj->head); }void myCircularQueueFree(MyCircularQueue* obj) //销毁队列的接口 {assert(obj);//利用头指针来完成链表节点的释放ListNode * endpoint = obj->head; //记录一个节点释放的终点obj->head = obj->head->next;while(obj->head!=endpoint){ListNode * tem = obj->head->next;free(obj->head);obj->head = tem;}free(endpoint); //释放掉终点节点free(obj); //释放掉维护环形队列的结构体 }leetcode题解测试:
相关文章:
数据结构:循环队列的实现(leetcode622.设计循环队列)
目录 一.循环队列简单介绍 二.用静态数组实现循环队列 1.数组循环队列结构设计 2.数组循环队列的堆区内存申请接口 3.数据出队和入队的接口实现 4.其他操作接口 5.数组循环队列的实现代码总览 三.静态单向循环链表实现循环队列 1.链表循环队列的结构设计 2.创建静…...
[qiankun]实战问题汇总
[qiankun]实战问题汇总ERROR SyntaxError: Cannot use import statement outside a module问题分析解决方案子应用命名问题问题分析解决方案jsonpFunction详细错误信息问题分析解决方案微应用的注册问题Uncaught Error: application cli5-beta6-test-name died in status LOADI…...
Kafka(6):服务端常用参数配置
参数配置:config/server.properties # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership.…...
2023爱分析·云原生智能运维中台市场厂商评估报告:秒云(miaoyun.io)
目录 1. 研究范围定义 2. 云原生智能运维中台市场定义 3. 厂商评估:秒云(miaoyun.io) 4. 入选证书 1. 研究范围定义 数字化时代,应用成为企业开展各项业务的落脚点。随着业务的快速发展,应用的功能迭代变得越…...
hadoop容器化部署
1、原容器 java:openjdk-8u111-jre jre路径: /usr/lib/jvm/java-8-openjdk-amd64 /usr/lib/jvm/java-1.8.0-openjdk-amd64 2、安装ssh docker run -it --name hadoop-test java:openjdk-8u111-jre bash apt-get update apt-get install openssh service ssh start …...
【07-JVM面试专题-JVM运行时数据区的虚拟机栈你知道吗?它的基本结构是什么呢?你知道栈帧的结构吗?那你说说动态链接吧?】
JVM运行时数据区的虚拟机栈你知道吗?它的基本结构是什么呢?你知道栈帧的结构吗?那你说说动态链接吧? JVM运行时数据区的虚拟机栈你知道吗?它的基本结构是什么呢?你知道栈帧的结构吗?那你说说动态…...
Java性能优化-GC优化基础
GC优化基础 调整堆大小 如果在FULL GC系统进行了交换,停顿时间会增长几个数量级,OS 如果G1 GC和后台进程处理堆,将会出现等待数据从磁盘复制到主内存时间较长,速度和下降并且并发模式可能失效 linux 关闭交换区 swapoff -a linu…...
【Tomcat】IDEA编译Tomcat源码-手把手教程
一、环境准备Tomcat不同版本之间有一定的兼容性问题~如下图所示:官网地址:https://tomcat.apache.org/whichversion.html下载tomcat9官网上面的源码:这一篇文章主要是带着大家在自己的IDEA跑起来一个Tomcat。使用的版本是Tomcat9.0.55 和 JDK…...
如何弄小程序?公司企业可以这样做小程序
公司企业现在对于小程序的需求已经是刚需了,即使已经有官网的情况下,也会考虑再弄一个小程序来做小程序官网。那么公司企业如何弄小程序呢?下面跟大家说说方法。 流程一、找小程序服务商 由于一些公司企业并不像现在的互联网公司企业那样有…...
【Git】IDEA集合Git和码云
目录 7、IDEA集合Git 7.1 配置Git忽略文件-IDEA特定文件 7.2 定位 Git 程序 7.3 初始化本地库 7.4 添加到暂存区 7.5 提交到本地库 7.6 切换版本 7.7 创建分支 7.8 切换分支 7.9 合并分支 7.10 解决冲突 8、 Idea集成码云 8.1 IDEA 安装码云插件 8.2 分析工程到码…...
[USACO03FALL / HAOI2006] 受欢迎的牛 G(C++,强连通分量)
题目背景 本题测试数据已修复。 题目描述 每头奶牛都梦想成为牛棚里的明星。被所有奶牛喜欢的奶牛就是一头明星奶牛。所有奶牛都是自恋狂,每头奶牛总是喜欢自己的。奶牛之间的“喜欢”是可以传递的——如果 AAA 喜欢 BBB,BBB 喜欢 CCC,那么…...
Vue 动态路由接口数据结构化为符合VueRouter的声明结构及菜单导航结构、动态路由懒加载方法
Vue 动态路由接口数据结构化为符合VueRouter的声明结构及菜单导航结构、动态路由懒加载方法 实现目标 项目打包代码实现按需分割路由懒加载按需打包,排除引入子组件的冗余打包(仅处理打包冗余现象,不影响生产部署)解决路由懒加载…...
Python----------字符串
1.转义字符 注:转义字符放在你所想效果字符前 2.原始字符串 print(r"D:\three\two\one\now") ->D:\three\two\one\now注: 在使用原始字符串时,转义字符不再有效,只能当作原始的字符,每个字符都没有特殊…...
日志收集笔记(架构设计、Log4j2项目初始化、Lombok)
1 架构设计 ELK 技术栈架构设计图: 从左往右看, Beats:主要是使用 Filebeat,用于收集日志,将收集后的日志数据发送给 Kafka,充当 Kafka 的生产者Kafka:高性能消息队列,主要起缓冲…...
一文教你玩转 Apache Doris 分区分桶新功能|新版本揭秘
数据分片(Sharding)是分布式数据库分而治之 (Divide And Conquer) 这一设计思想的体现。过去的单机数据库在大数据量下往往面临存储和 IO 的限制,而分布式数据库则通过数据划分的规则,将数据打散分布至不同的机器或节点上…...
数据挖掘,计算机网络、操作系统刷题笔记54
数据挖掘,计算机网络、操作系统刷题笔记54 2022找工作是学历、能力和运气的超强结合体,遇到寒冬,大厂不招人,可能很多算法学生都得去找开发,测开 测开的话,你就得学数据库,sql,orac…...
将数组中的每个元素四舍五入到指定的精度numpy.rint()
【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 将数组中的每个元素 四舍五入到指定的精度 numpy.rint() 选择题 请问np.rint(a)的输出结果是? import numpy as np anp.array([-1.72,-1.3,0.37,2.4]) print("【显示】a:\n…...
Web安全之服务器端请求伪造(SSRF)类漏洞详解及预防
如何理解服务器端请求伪造(SSRF)类漏洞当服务器向用户提交的未被严格校验的URL发起请求的时候,就有可能会发生服务器端请求伪造(SSRF,即Server-Side Request Forgery)攻击。SSRF是由攻击者构造恶意请求URL&…...
LeetCode:239. 滑动窗口最大值
239. 滑动窗口最大值 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 示例 1: 输入:nums [1,3,-…...
JS 函数参数(动态参数、剩余参数)
需求:求和函数 传入不同实参 求和出来1.动态参数 arguments 只存在于函数内function getSum() {//arguments 获取传递的所有参数 是一个伪数组let num 0for(let i0;i<arguments.length;i){num arguments[i]}return num}//调用console.log(getSum(1,2,3))consol…...
安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...
最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...
自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...
如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...
Linux 中如何提取压缩文件 ?
Linux 是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的,要在 …...
人工智能 - 在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型
在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型。这些平台各有侧重,适用场景差异显著。下面我将从核心功能定位、典型应用场景、真实体验痛点、选型决策关键点进行拆解,并提供具体场景下的推荐方案。 一、核心功能定位速览 平台核心定位技术栈亮…...
Linux 下 DMA 内存映射浅析
序 系统 I/O 设备驱动程序通常调用其特定子系统的接口为 DMA 分配内存,但最终会调到 DMA 子系统的dma_alloc_coherent()/dma_alloc_attrs() 等接口。 关于 dma_alloc_coherent 接口详细的代码讲解、调用流程,可以参考这篇文章,我觉得写的非常…...




另外一种情形:





另外一种队列判满的情形:





