数据结构:循环队列的实现(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…...

365天深度学习训练营-第J3周:DenseNet算法实战与解析
目录 一、前言 二、论文解读 1、DenseNet的优势 2、设计理念 3、网络结构 4、与其他算法进行对比 三、代码复现 1、使用Pytorch实现DenseNet 2、使用Tensorflow实现DenseNet网络 四、分析总结 一、前言 🍨 本文为🔗365天深度学习训练营 中的学习…...

Parisland NFT 作品集
该作品集用来自 Parisland 体验,共包含 11 个 NFT 资产,把你的土地装扮成一个眼花缭乱的热带天堂吧! 登上芭黎丝的爱情船和戴上豪华的螺旋爱情戒指,成为她在数位世界举办的真人秀的一部分吧!该系列还包含两个传奇级别的…...

uniapp: 基础开发官网文档
1、uniapp官网文档:https://uniapp.dcloud.net.cn/component/2、uView跨端UI组件库:http://v1.uviewui.com/components/intro.html3、lunch-request(类似axios的请求库):https://www.quanzhan.co/luch-request/handboo…...

mybatis中配置连接池的原理介绍分析
1.连接池:我们在实际开发中都会使用连接池。因为它可以减少我们获取连接所消耗的时间。2、mybatis中的连接池mybatis连接池提供了3种方式的配置:配置的位置:主配置文件SqlMapConfig.xml中的dataSource标签,type属性就是表示采用何…...

二叉树——路径总和
路径总和 链接 给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。 叶子节点…...

WebDAV之π-Disk派盘+文件管理器
文件管理器 支持WebDAV方式连接π-Disk派盘。 推荐一款iOS上的免费文件管理器新秀。 文件管理器这是一款功能强大的文件管理工具,支持zip,rar,7z等压缩包的解压和压缩,支持小说,漫画,视频下载及播,极大提升日常办公,娱乐,文件管理的工作效率,使得文档的归档和管理随心…...

form表单单输入框回车提交事件处理
问题 form表单中如果只有一个输入框,在输入时按Enter回车键会出发默认事件自动提交表单,该交互是同步发生的,会导致页面刷新。 解决思路 有三种解决思路: 1. 增加input输入框的数量 如果form表单中不止一个input输入框&#…...

c++常用stl算法
1、头文件 这些算法通常包含在头文件<algorithm> <functional> <numeric>中。 2、常用遍历算法 for_each(v.begin(),v.end(), 元素处理函数/仿函数) 注意:在使用transform转存时,目标容器需要提取开辟合适的空间。 void printfunc(…...

非对称密钥PKCS#1和PKCS#8格式互相转换(Java)
目录一、序言二、代码示例1、Maven依赖2、工具类封装三、测试用例1、密钥文件2、公私钥PKCS1和PKCS8格式互相转换一、序言 之前在 《前后端RSA互相加解密、加签验签、密钥对生成》 中提到过PKCS#1格式和PKCS#8格式密钥的区别以及如何生成密钥。实际有些场景中有可能也会涉及到…...

java获取当前时间的方法:LocalDateTime、Date、Calendar,以及三者的比较
文章目录前言一、LocalDateTime1.1 获取当前时间LocalDate.now()1.2 获取当前时间的年、月、日、时分秒localDateTime.getYear()……1.3 给LocalDateTime赋值LocalDateTime.of()1.4 时间与字符串相互转换LocalDateTime.parse()1.5 时间运算——加上对应时间LocalDateTime.now()…...