队列概念|循环队列的实现
前言
今天我们将学习循环队列实现,我们首先介绍队列的概念和结构,之后一步步讲解循环队列由来与实现。
一、队列的概念与结构
1、队列的概念
队列: 只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表。队列是一种先进先出FIFO(first in first out)的线性表,允许插入的一端称为队尾,允许删除的一端称为队头。(这种结构很符合我们生活中的习惯,排在第一个的优先出列,最后来的当然就在队伍最后。)
2、队列的结构

3、实例
比如: ①键盘的输入:输入“abc”,输出也是“abc”;②生活中的排队等等。
二、循环队列
1、队列的实现方式有两种
线性表有顺序存储和链式存储。同样,队列作为一种特殊的线性表,也同样存在这两种存储方式。
2、队列顺序存储的不足
队列的顺序存储其实就是使用数组来实现。数组实现队列,一般数组下标为0的一端为队头,数组尾为队尾。
入队: 入队是在队尾插入数据,即在数组尾追加一个数据,不需要移动数据,所以时间复杂度为O(1)。如下图:

出队: 出队是在队头删除数据,即数组的头删,需要挪动后面的所有元素,保证所有元素都从队头出去,此时时间复杂度为O(N)。如下图:

但是每一次出队列都需要挪动数据,效率不太好。那能不能不将队头的位置固定在下标为0的位置,即每出队列一次,队头向后跳过一个元素,此时时间复杂度为O(1)。如下图:

使用这种方法出队列,虽然效率提高了,但又引出了一个新问题——“假溢出”。
假溢出: 如下图,假设队列的总个数为5,当数组末尾的空间已经被占用了,此时再入队,就会产生数组越界的问题,可实际上,我们队列在下标0、1、2的地方还是空闲的。这种现象就叫做“假溢出”。

那“假溢出”有没有解决方案呢?
答案是:有的,有三种解决方案。
①当队列满了,就扩容。但缺点就是空间利用率低。
②不改变队头的位置,挪动数据。缺点:时间复杂度为O(N)。
③循环队列。优点:效率高。(缺点实在来说就只有,队列大小实现前要确定好。)
3、循环队列的定义
循环队列: 我们把队头与队尾是相互链接的队列称为循环队列。因为循环队列首尾相连,所以只要队列没有满就可以插入数据,不会产生假溢出问题。
理解: ①队列的大小要事先确定;②队列首尾相连。
实现:①顺序存储实现;②链式存储实现。这两种实现方式哪种更好呢?
答案是:顺序存储实现更好。假设队列大小为5,队首指针为front,队尾指针的下一个为rear,分析如下:
①链式存储实现:
问题1:队列空与队列满情况一样,如下图:

解决方案:
①队列成员加一个成员size变量储存有效数据个数——>队列满:size == k;队列空:size == 0。
②队列多开辟一个空间——>队列满:rear->next == front;队列空:rear == front。(这里我们使用方案2解决。)
问题2:取队尾元素不好取,如下图:

解决方案:①双向链表;②队列加一个成员变量prev储存rear的前驱结点。
②顺序存储实现:
问题1:怎么实现首尾相连,即rear与front到了下标k的位置怎么回到下标0的位置。

tip:
①取队尾:(rear - 1 + k + 1)% (k + 1)

②队列满:(rear + 1)% (k + 1)== front,队列空:rear == front

总结: 由上分析可知,链式存储对比顺序存储的劣势有:①多一个指针域,浪费空间;②不好找队尾元素;③代码实现复杂等等。所以下面我们将使用顺序存储实现循环队列。
4、循环队列的实现
队列的实现,应该支持如下操作:
- MyCircularQueue(k):构造器,在堆区申请队列对象,初始化队首、队尾指针、队列长度。
- Front:获取队首元素。如果队列为空,返回-1。
- Rear:获取队尾元素。如果队列为空,返回-1。
- enQueue(value):入队列——队尾插入一个元素。如果成功插入返回真。
- deQueue():出队列——队头删除元素。如果成功删除返回真。
- isEmpty():检查队列是否为空。
- isFull():检查队列是否已满。
- Free():销毁队列。
循环队列在力扣有题目,大家可以先去做一做。链接在下面。
循环队列链接
循环队列的代码实现:
//循环队列的结构
typedef struct
{int* a;//指向堆区开辟的数组int front;//队首指针——表示队首位置int rear;//队尾指针——表示队尾的下一个int length;//队列长度
} MyCircularQueue;//初始化——在堆区开辟队列对象与队列空间,并初始化队首与队尾,队列长度
MyCircularQueue* myCircularQueueCreate(int k)
{//在堆区开辟循环队列的对象MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));//判断是否开辟成功if(NULL == obj){//打印错误信息perror("malloc fail");return NULL;}//申请队列空间——为避免队列满与空情况一样,队列多开辟一个空间obj->a = (int*)malloc(sizeof(int) * (k + 1));//判断是否开辟成功if(NULL == obj){//打印错误信息perror("malloc fail");return NULL;}//初始化队首、队尾指针obj->front = 0;obj->rear = 0;//初始化队列长度obj->length = k + 1;//返回在堆区开辟循环队列对象return obj;
}
//检查队列是否已满,满返回真
bool myCircularQueueIsFull(MyCircularQueue* obj)
{//断言obj不为空assert(obj);//相等则满return (obj->rear + 1) % obj->length == obj->front;
}//入队列:队尾插入数据,成功返回真
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
{assert(obj);//调用myCircularQueueIsFull判断队列是否满if(myCircularQueueIsFull(obj)){return false;//满,直接返回假}//队尾插入数据obj->a[obj->rear] = value;//插入之后,rear+1obj->rear++;//rear每一次+1后,防止越界,当rear = k时,取模回到下标0obj->rear %= obj->length;//插入成功返回真return true;
}
//检查队列是否为空
bool myCircularQueueIsEmpty(MyCircularQueue* obj)
{assert(obj);//相等队列为空return obj->rear == obj->front;
}
//出队列:队头出队列,即front++,出队列成功返回真
bool myCircularQueueDeQueue(MyCircularQueue* obj)
{assert(obj);//调用myCircularQueueIsEmpty判断队列是否为空if(myCircularQueueIsEmpty(obj)){return false;}//删除队头,即front++obj->front++;//front每一次+1后,防止越界,即当front = k时,取模回到下标0obj->front %= obj->length;//出队列成功返回真return true;
}
//获取队首元素。如果队列为空,返回 -1 。
int myCircularQueueFront(MyCircularQueue* obj)
{assert(obj);//调用myCircularQueueIsEmpty判断队列是否为空if(myCircularQueueIsEmpty(obj)){//为空,返回-1return -1;}//不为空返回队首元素return obj->a[obj->front];
}
//获取队尾元素。如果队列为空,返回 -1 。
int myCircularQueueRear(MyCircularQueue* obj)
{assert(obj);//调用myCircularQueueIsEmpty判断队列是否为空if(myCircularQueueIsEmpty(obj)){//为空,返回-1return -1;}//返回队尾元素,rear为队尾的下一个,(rear - 1 + obj->length) % obj->length)即为队尾位置,注意不能使用--操作符return obj->a[(obj->rear - 1 + obj->length) % obj->length];
}
//销毁队列
void myCircularQueueFree(MyCircularQueue* obj)
{assert(obj);//注意销毁的顺序,要先释放队列结构中的数组,再释放队列对象free(obj->a);//free之后,obj->a指向不变,防止野指针,置为空obj->a = NULL;free(obj);obj = NULL;
}
希望对大家有帮助,循环队列就讲解完成了。循环队列有个缺点就是必须先开辟队列空间,队列的大小实现就要确定好,那有没有队列空间按需提供的呢?答案是:有的,就是链式队列。在下一期作者会对其详细讲解。
相关文章:
队列概念|循环队列的实现
前言 今天我们将学习循环队列实现,我们首先介绍队列的概念和结构,之后一步步讲解循环队列由来与实现。 一、队列的概念与结构 1、队列的概念 队列: 只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表。队列是…...
监控数据控中的数据表
背景: 在做一个项目的时候,每次代码分析的数据会写入到数据库,目前想实现当数据插入到数据库后,对新插入的数据进行监控解析。当有一个新纪录插入到数据表的时候,数据库可以自动解析新插入的数据记录。 思路如下&…...
进程替换..
1、单进程版 – 最简单的先看看程序替换 现象就是 1、我们用自己的进程封装了内置指令ls,并且代码中execl 后 printf 的after并没有打印出来。 2、谈进程替换的原理 单进程替换基本原理 上面例子中execl的做法非常简单粗暴,要调用ls,那么就把mycom…...
M1安装OpenPLC Editor
下载OpenPLC Editor for macOS.zip文件后,使用tar -zvxf命令解压,然后将"OpenPLC Editor"拖入到"应用程序"文件夹 右键点击"OpenPLC Editor",打开这个""文件,替换为以下内容 #!/bin/bash…...
STM32F10xx 存储器和总线架构
一、系统架构 在小容量、中容量和大容量产品 中,主系统由以下部分构成: 四个驱动单元 : Cotex-M3内核、DCode总线(D-bus)和系统总线(S-bus) 通用DMA1和通用DMA2 四个被动单元 内部SRAM 内部…...
并发编程
什么是并发编程? 并行:在同一个时间节点上,多个线程同时执行(是真正意义上的同时执行) 并发:一个时间段内,多个线程依次执行。 并发编程:在例如买票、抢购、秒杀等等场景下,有大量的请求访问…...
Lauterbach使用指南之RunTime功能
Lauterbach使用指南之RunTime功能 前言 首先,请问大家几个小小问题,你清楚: Lauterbach这个工具是干什么用的吗?在软件运行过程中如何测量两个运行point之间的runtime时间呢?Lauterbach的RunTime功能具体应当如何来操…...
GaussDB数据库管理系统介绍
1.GaussDB的发展 2.GaussDB的生态 内部: 云化自动化方案。通过数据库运行基础设施的云化将DBA(数据库管理员)和运维人员的日常工作 自动化。外部: 采用与数据库周边生态伙伴对接与认证的生态连接融合方案,解决开发者/DBA难获取、应用难对接等…...
使用docker部署lnmp多站点
1. 创建一个 Docker 网络 以便容器可以在同一网络上进行通信 docker network create lnmpnetwork2. 运行 MySQL 容器: 运行 MySQL 容器并将其连接到创建的网络。确保将 MySQL 的端口映射到宿主机上,以便您可以从宿主机访问数据库。 将mysql的配置和数…...
实例详解:Java使用JWT和Redis实现高效单点登录(SSO)
前言 单点登录(Single Sign-On,简称SSO)是一种身份验证和访问控制机制,允许用户使用一组凭证(如登录名和密码)登录到多个应用程序中,而无需为每个应用程序单独进行身份验证。用户只需要登录一次…...
SQL中使用ROLLUP和CUBE函数轻松生成汇总行
在数据分析和报表制作中,通常需要对数据进行汇总和分组,我们常用的就是GROUP BY汇总数据,当我们想按照不同维度汇总时,往往需要编写多个GROUP BY预计,而借助ROLLUP 和 CUBE 函数可以一次性生成子总计和总计行ÿ…...
CentOS 7 安装和配置java环境
1 安装包准备 安装包可以通过下面地址进行版本选择安装: https://www.oracle.com/java/technologies/downloads/#java8 2 正式开始安装 本次分享的安装方法直接通过编辑/etc/profile文件实现java的安装 2.1 新建安装包存放目录 mkdir /java cd /java/ 2.2 解压安…...
「实验记录」CS144 Lab0 networking warmup
文章目录 一、Motivation二、SolutionsS1 - Writing webgetS2 - An in-memory reliable byte stream 三、Results四、Source 一、Motivation 第一个小测试 webget 是想让我们体验并模拟一下在浏览器中键入 URL 后获得远程服务器传来的内容,这并没有太大的难度&…...
html5怎么实现语音搜索
html5怎么实现语音搜索 谷歌的网站在他们首页发现了HTML5的新玩法——语音搜索。 注意: 只有webkit核心的浏览器才能使用 用法很简单 只需要在input添加属性x-webkit-speech即可,例子如下: 代码如下: <input type"text" x-…...
吴恩达《机器学习》1-2:什么是机器学习?
一、什么是机器学习? Arthur Samuel(1959): 他定义机器学习为,在进行特定编程的情况下,给予计算机学习能力的领域。 Tom Mitchell(1998): 他定义的机器学习是,…...
基于STC系列单片机实现定时器扫描数码管显示定时器/计数器产生频率的功能
#define uchar unsigned char//自定义无符号字符型为uchar #define uint unsigned int//自定义无符号整数型为uint #define NixieTubeSegmentCode P0//自定义数码管段码为单片机P0组引脚 #define NixieTubeBitCode P2//自定义数码管位码为单片机P2组引脚 sbit LED P1^0;//位定义…...
Linux环境开发工具yum、makefile的使用 【Linux】
文章目录 Linux软件包管理器 - yumLinux下安装软件的方式yum查找软件包如何实现本地机器和云服务器之间的文件互传卸载软件Linux编译器 - gcc/g 程序的翻译过程1.预编译(预处理)2.编译(生成汇编)3.汇编(生成机器可识别…...
第六章(6):Python中的函数—闭包和装饰器
1.闭包 在Python中,闭包是指函数与其相关的自由变量的一个整体。当一个函数返回了一个内部函数时,这个内部函数可以访问其定义所在的外部函数中的变量,即使这个外部函数已经返回了。这种特性就叫做闭包。 代码示意: def funca():x = 250def funcb():print(我仍然可以访问…...
Linux--安装与配置虚拟机及虚拟机服务器坏境配置与连接---超详细教学
一,操作系统介绍 1.1.什么是操作系统 操作系统(Operating System,简称OS)是一种系统软件,它是计算机硬件和应用软件之间的桥梁。它管理计算机的硬件和软件资源,为应用程序提供接口和服务,并协调…...
基于SSM的个性化美食推荐系统设计与实现
末尾获取源码 开发语言:Java Java开发工具:JDK1.8 后端框架:SSM 前端:采用JSP技术开发 数据库:MySQL5.7和Navicat管理工具结合 服务器:Tomcat8.5 开发软件:IDEA / Eclipse 是否Maven项目&#x…...
PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建
制造业采购供应链管理是企业运营的核心环节,供应链协同管理在供应链上下游企业之间建立紧密的合作关系,通过信息共享、资源整合、业务协同等方式,实现供应链的全面管理和优化,提高供应链的效率和透明度,降低供应链的成…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
#Uniapp篇:chrome调试unapp适配
chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...
音视频——I2S 协议详解
I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议,专门用于在数字音频设备之间传输数字音频数据。它由飞利浦(Philips)公司开发,以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...
宇树科技,改名了!
提到国内具身智能和机器人领域的代表企业,那宇树科技(Unitree)必须名列其榜。 最近,宇树科技的一项新变动消息在业界引发了不少关注和讨论,即: 宇树向其合作伙伴发布了一封公司名称变更函称,因…...
Chrome 浏览器前端与客户端双向通信实战
Chrome 前端(即页面 JS / Web UI)与客户端(C 后端)的交互机制,是 Chromium 架构中非常核心的一环。下面我将按常见场景,从通道、流程、技术栈几个角度做一套完整的分析,特别适合你这种在分析和改…...
嵌入式常见 CPU 架构
架构类型架构厂商芯片厂商典型芯片特点与应用场景PICRISC (8/16 位)MicrochipMicrochipPIC16F877A、PIC18F4550简化指令集,单周期执行;低功耗、CIP 独立外设;用于家电、小电机控制、安防面板等嵌入式场景8051CISC (8 位)Intel(原始…...
用鸿蒙HarmonyOS5实现中国象棋小游戏的过程
下面是一个基于鸿蒙OS (HarmonyOS) 的中国象棋小游戏的实现代码。这个实现使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chinesechess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├──…...
面试高频问题
文章目录 🚀 消息队列核心技术揭秘:从入门到秒杀面试官1️⃣ Kafka为何能"吞云吐雾"?性能背后的秘密1.1 顺序写入与零拷贝:性能的双引擎1.2 分区并行:数据的"八车道高速公路"1.3 页缓存与批量处理…...
