队列概念|循环队列的实现

news2024/12/23 12:23:36

前言

今天我们将学习循环队列实现,我们首先介绍队列的概念和结构,之后一步步讲解循环队列由来与实现。

一、队列的概念与结构

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+1
    obj->rear++;
    //rear每一次+1后,防止越界,当rear = k时,取模回到下标0
    obj->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时,取模回到下标0
    obj->front %= obj->length;
    //出队列成功返回真
    return true;
}
//获取队首元素。如果队列为空,返回 -1 。
int myCircularQueueFront(MyCircularQueue* obj) 
{
    assert(obj);
    //调用myCircularQueueIsEmpty判断队列是否为空
    if(myCircularQueueIsEmpty(obj))
    {
        //为空,返回-1
        return -1;
    }
    //不为空返回队首元素
    return obj->a[obj->front];
}
//获取队尾元素。如果队列为空,返回 -1 。
int myCircularQueueRear(MyCircularQueue* obj) 
{
    assert(obj);
    //调用myCircularQueueIsEmpty判断队列是否为空
    if(myCircularQueueIsEmpty(obj))
    {
        //为空,返回-1
        return -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;
}

希望对大家有帮助,循环队列就讲解完成了。循环队列有个缺点就是必须先开辟队列空间,队列的大小实现就要确定好,那有没有队列空间按需提供的呢?答案是:有的,就是链式队列。在下一期作者会对其详细讲解。

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

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

相关文章

3.72 Command Buffer及URP概述

一、Command Buffer 1.概念 CommandBuffer携带一系列的渲染命令,依赖相机,用来拓展渲染管线的渲染效果。而且可以指定在相机渲染的某个点执行本身的拓展渲染。Command buffers也可以结合屏幕后期效果使用。 简单来说就是可以在渲染流程中插入一些自定…

群智能算法之模拟退火算法

1.模拟退火算法简介: 2.模拟退火算法的关键点: (1)随机的更新可行解x,判断可行解x对应的函数值和原来函数值之间的大小:如果优于原来的函数值,则让新的可行解x为问题的解;否则以一定的概率(大于…

centos7 部署 Flink

1. 准备 安装的前提是虚拟机里已安装了jdk 去官网下载 Flink 所有版本下载地址:https://archive.apache.org/dist/flink/ 找到下图的安装包,下载即可 下载完后,将其上传至虚拟机的某个地方,本人将其放在 /home/flink/ 下 解压…

nacos面试题

Nacos中保证的是CP还是AP? 通常我们说,Nacos技能保证CP,也能保证AP,具体看如何配置,但其实只不过是Nacos中的注册中心能保证CP或AP,Nacos中的配置中心其实没什么CP或AP,因为配置中心的数据是存在…

2023.10.28 关于 synchronized 原理

目录 synchronized 特性 synchronized 优化机制 锁升级(锁膨胀) 其他优化机制 锁消除 锁粗化 synchronized 特性 开始时是乐观锁,如果锁冲突频繁,就转为悲观锁开始是轻量级锁,如果锁被持有的时间较长&#xff0c…

水果百科网站 vue+uniapp微信小程序设计与实现

设计并实现了鲜而廉水果微信小程序。系统选用java语言,应用Springboot框架, MySQL为后台数据库。系统主要包括用户、水果百科、水果视频、交流论坛等功能模块。 经过认真细致的研究,精心准备和规划,最后测试成功,系统可…

[导弹打飞机H5动画制作]飞机与导弹的碰撞检测

界面参考: 代码参考: this.btnShootTruck.addEventListener("click", startShoot); var _this = this; _this.ShootFire.stop(); _this.ShootFire.alpha = 0; //_this.AsyPlaneObj.gotoAndStop(0); _this.AsyPlaneObj.alpha = 1; _this.AsyPlaneObj.BombPlaneObj.al…

【vtk学习笔记2】vtk编程中的基本对象

一、VTK编程中的基本对象 数据可视化一般需要一个数据源,可以来说具体的算法,如有限元、边界元等,也可以是测量数据,如医学检测数据等。这些基础数据经过变换处理,变成计算机图形流水线支持的数据,最后显示…

redis实现分布式延时队列

文章目录 延时队列简介应用场景案例:考虑:实现:整体思路:具体实现生产者消费者 运行结果 redis分布式延时队列优势redis分布式延时队列劣势 延时队列简介 延时队列是一种特殊的消息队列,它允许将消息在一定的延迟时间…

【系统安全】等保二级、三级自查对比

目录 1、定义:二级 VS 三级 2、要求:二级 VS 三级 3、适用企业、单位 1、定义:二级 VS 三级 等保:全称网络安全等级保护,是指对信息系统进行分级,对不同等级的信息系统进行不同的安全保护和监管的工作。…

仿写知乎日报第二周

新学到的 新学到了WKWebView&#xff1a; WKWebView是是苹果推崇的一个新的类&#xff0c;它用于将一个网页嵌套在软件里。这里我是将点击cell后的内容中放入WKWebView对象。WKWebView的使用&#xff1a; 首先&#xff0c;要导入这个类&#xff1a; #import <WebKit/WebK…

3.7 移动端TB(D)R架构基础

一、各类电子设备功耗对比 桌面级主流性能平台&#xff0c;功耗一般为300W&#xff08;R7/I7X60级别显卡&#xff09;&#xff0c;游戏主机150-200W入门和旗舰游戏本平台功耗为100W主流笔记本为50-60W&#xff0c;超极本为15-25W&#xff0c;旗舰平板为8-15W旗舰手机为5-8W&am…

《python语言程序设计》(2018版)第5章编程题 第41题第3次路过。总结一下。没有走完的路

这道题最大的需要就是能够进行两个数值的对比&#xff0c;同时还能让更多的数值依次进入到对比中。 这道题的解题版本 这个版本只是能统计出谁是最大数。但是无法统计最大数出现了多少次。 number "" count 0 data_number 0 while number ! 0:number eval(inpu…

No172.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

MinIO安装

Minio是一个开源的分布式对象存储服务器&#xff0c;它兼容Amazon S3服务接口。它可以用于构建私有云存储&#xff0c;为应用程序提供可扩展的对象存储功能。 安装 docker安装 docker run -d -p 9000:9000 -p 50000:50000 --name minio \ -e "MINIO_ROOT_USERadminpili…

泰州市旅游景点门票预订管理系统 vue+uniapp微信小程序

本文从管理员、用户的功能要求出发&#xff0c;泰州市旅游景点管理小程序中的功能模块主要是实现用户、景点类型、景区信息、门票预定。经过认真细致的研究&#xff0c;精心准备和规划&#xff0c;最后测试成功&#xff0c;系统可以正常使用。分析功能调整与泰州市旅游景点管理…

Leetcode—275.H指数II【中等】

2023每日刷题&#xff08;十三&#xff09; Leetcode—275.H指数II 算法思想 实现代码 int minValue(int a, int b) {return a < b ? a : b; }int hIndex(int* citations, int citationsSize){int left, right;left 0;right citationsSize - 1;while(left < right) …

AD教程(一)工程组成及创建

AD教程&#xff08;一&#xff09;工程组成及创建 工程组成 原理图库 绘制电阻模型、芯片模型、电容模型等&#xff0c;即将元件模型绘制出来。 原理图 将绘制的原件模型放置到原理图中&#xff0c;然后再添加连接的导线、网络标号。器件和器件之间的连接关系&#xff0c;在原…

粤嵌实训医疗项目--day04(Vue + SpringBoot)

往期回顾 粤嵌实训医疗项目--day03&#xff08;Vue SpringBoot&#xff09;-CSDN博客粤嵌实训医疗项目day02&#xff08;Vue SpringBoot&#xff09;-CSDN博客粤嵌实训医疗项目--day01&#xff08;VueSpringBoot&#xff09;-CSDN博客 目录 一、用户详细信息查询 (查询信息与…

业务设计——用户敏感信息展示脱敏及其反脱敏

业务需求 将用户敏感信息脱敏展示到前端是出于保护用户隐私和信息安全的考虑。 敏感信息包括但不限于手机号码、身份证号、银行卡号等&#xff0c;这些信息泄露可能导致用户个人信息的滥用、身份盗用等严重问题。脱敏是一种常用的保护用户隐私的方式&#xff0c;它的目的是减少…