《数据结构与算法之美》学习笔记五之队列

前情提要:上一章学习了栈相关的知识,主要有下面的内容:
  • 栈操作的时间复杂度,对于顺序栈,入栈时如果栈的空间不够涉及到数据搬移,此时使用摊还分析法,将数据搬移的耗时均摊到不需要搬移数据的入栈操作中,均摊时间复杂度等于最好情况时间复杂度 O(1)
  • 栈在函数调用中的应用,内存给每一个线程都分配了一块独立的内存空间,这些内存空间被组织成“栈”的形式,用来存储函数调用时的临时变量,当进入一个函数时,会将这个函数作为一个栈帧入栈,当函数执行完毕时,会将对应的栈帧出栈。
  • 栈在表达式中的应用,对于加减乘除等等数学表达式的运算,计算机理解起来是很困难的,需要使用栈来辅助。需要一个运算符栈和一个操作数栈,遍历表达式,当遇到操作数,就压入操作数栈,当遇到运算符,则需要和运算符栈的栈顶运算符比较优先级,如果栈顶元素优先级高,如果当前运算符优先级更高,就压入运算运算符栈,继续下次对比;
  • 如何使用栈实现浏览器的前进后退功能?和计算表达式的值有点类似,也是需要两个栈,当访问新页面的时候,把页面压入栈A;当点击后退时,取出栈A的栈顶元素,压入栈B;当点击前进时,从栈B中取出栈顶元素,压入栈A;如果要访问新页面,就需要清除栈B

这一章继续来学习队列
队列比栈复杂那么一丢丢

(一)队列基本概念

队列的基本概念很好理解,就类似于买票排队,先来的先买,后来的排到队尾,也就是咱们经常听到的“先进先出”
队列与栈类似,也只支持两种操作:“入队” 和 “出队”。“入队” 就是新增一个元素到队列的末尾,“出队” 就是从队列的头部取出一个元素。
在这里插入图片描述
所以队列和栈一样,是一种操作受限的线性表数据结构。

(二)顺序队列和链式队列

跟栈一样,队列也可以用数组和链表实现。用数组实现的叫顺序队列,用链表实现的叫链式队列
下面是使用 Java 语言写的队列的数组实现

// 用数组实现的队列
public class ArrayQueue {// 数组:items,数组大小:nprivate String[] items;private int n = 0;// head表示队头下标,tail表示队尾下标private int head = 0;private int tail = 0;// 申请一个大小为capacity的数组public ArrayQueue(int capacity) {items = new String[capacity];n = capacity;}// 入队public boolean enqueue(String item) {// 如果tail == n 表示队列已经满了if (tail == n) return false;items[tail] = item;++tail;return true;}// 出队public String dequeue() {// 如果head == tail 表示队列为空if (head == tail) return null;// 为了让其他语言的同学看的更加明确,把--操作放到单独一行来写了String ret = items[head];++head;return ret;}
}

队列的数组实现比栈的数组实现复杂了那么一丢丢。
对于栈来说,只需要一个栈顶指针,因为入栈出栈都是在栈顶进行操作。而队列需要一个队头指针 head 和一个队尾指针 tail 。可以结合下面这张图来理解
在这里插入图片描述
当 a b c d 依次入队之后,队列的 head 指针就指向索引为0的位置,tail 指针就指向索引为4的位置。
当我们调用了两次出队操作之后,head指针往后移动两位,指向索引为2的位置,tail指针还是指向索引为4的位置
在这里插入图片描述
随着不停地入队、出队操作,head 指针和 tail 指针都会往后移动,如果这两个指针重合,即使数组中还有位置,也没办法再进行入队操作了。
回想一下数组那一章节,删除一个元素,造成数组空间不连续,后续再往数组中增加元素的时候,这个空出来的空间是没有办法利用的。此时我们怎么解决数据不连续的问题呢?对,就是使用数据搬移
每次的出队操作都相当于删除了索引为0的元素。但是我们并不需要在每次出队的时候都进行数据搬移,这样子会导致出队的时间复杂度变为 O(n),只需要在入队时,发现没有空闲空间的时候,进行数据搬移。
这样子的话,队列的出队函数并不需要修改,入队函数需要修改一下下

// 入队操作,将item放入队尾
public boolean enqueue(String item) {// tail == n表示队列末尾没有空间了if (tail == n) {// tail ==n && head==0,表示整个队列都占满了if (head == 0) return false;// 数据搬移for (int i = head; i < tail; ++i) {items[i-head] = items[i];}// 搬移完之后重新更新head和tailtail -= head;head = 0;}items[tail] = item;++tail;return true;
}

从代码中可以看到,当队列的 tail 指针移动到最右边后,再往队列中添加元素时,就会将 head 指针到 tail 指针之间的数据往前搬移,从索引为0开始,到 tail - head 结束
在这里插入图片描述
在这种实现思路下,出队操作的时间复杂度仍然是 O(1)。入队操作,我们之前在数组那一章节分析过,均摊时间复杂度就等于最好情况时间复杂度,也是 O(1)。
接下来我们再来看一下基于链表的队列实现方式。
基于链表的实现,我们同样需要两个指针,head 指针指向链表的第一个结点,tail 指针指向链表的最后一个结点。如下图所示,
入队时,tail.next = newNode;tail = tail.next
出队时,head = head.next

在这里插入图片描述

(三)循环队列

循环队列,顾名思义,就是原来的拉直的队列首尾相连成一个圈圈
在这里插入图片描述
我们可以发现,图中的队列大小为8,head指针指向 4 的位置,tail 指针指向 7 的位置。
当有一个新元素入队的时候,新元素会放在 7 的位置,tail 指针并不需要更新为 8 ,而是需要到 0 的位置,同样的,再次新增时,tail 指针继续往前移动,到 1 的位置。新增两个元素的状态如下图所示:
在这里插入图片描述
通过这种方式,在队列空间满之前,都不需要进行数据搬移操作。
但是循环队列的实现,相比于非循环队列,会复杂一些。关键在于两个状态的确定,一个是队列为空的状态,一个是队列满员的状态。
在非循环的队列中,队列为空的判断标准是 head == tail ,队列满员的判断标准是 tail == n
在循环队列中,队列为空的判断条件依然是 head == tail,队列满员的状态如下图所示
在这里插入图片描述
队列满员的判断条件,可以通过多🖼几次图总结出来,是 (tail+1)%n=head。当队列满的时候,tail 的位置是没有存储数据的,这会造成一丢丢内存的浪费。

public class CircularQueue {// 数组:items,数组大小:nprivate String[] items;private int n = 0;// head表示队头下标,tail表示队尾下标private int head = 0;private int tail = 0;// 申请一个大小为capacity的数组public CircularQueue(int capacity) {items = new String[capacity];n = capacity;}// 入队public boolean enqueue(String item) {// 队列满了if ((tail + 1) % n == head) return false;items[tail] = item;tail = (tail + 1) % n;return true;}// 出队public String dequeue() {// 如果head == tail 表示队列为空if (head == tail) return null;// 取出头部String ret = items[head];// 更新head到前一个位置head = (head + 1) % n;return ret;}
}

(四)阻塞队列

阻塞队列其实就是在队列的基础上增加了阻塞操作。当队列为空的时候,从对头取数据的操作就会被阻塞,等到队列中有数据的时候,在从队头取出数据并返回;入队操作也一样,当队列满的时候,入队操作会被阻塞,等到队列中有空位的时候才会执行插入操作,并返回。
在这里插入图片描述

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

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

相关文章

【YOLO学习】YOLOv1详解

文章目录 1. 概述2. 算法流程3. 网络结构4. 损失函数 1. 概述 1. YOLO 的全称是 You Only Look Once: Unified, Real-Time Object Detection。YOLOv1 的核心思想就是利用整张图作为网络的输入&#xff0c;直接在输出层回归 bounding box 的位置和 bounding box 所属的类别。简单…

【二十五】【QT开发应用】无边窗窗口鼠标拖动窗口移动,重写mousePressEvent,mouseMoveEvent函数

在 Qt 中&#xff0c;可以通过在自定义的类中重载 mousePressEvent 和 mouseMoveEvent 函数来捕获鼠标按下和移动事件&#xff0c;以便实现例如拖动窗口等功能。 mousePressEvent 和 mouseMoveEvent分别是鼠标按下事件和鼠标移动事件。这两个函数是QT中本身就存在的函数&#…

【2023工业图像异常检测文献】SimpleNet

SimpleNet:ASimpleNetworkforImageAnomalyDetectionandLocalization 1、Background 图像异常检测和定位主要任务是识别并定位图像中异常区域。 工业异常检测最大的难题在于异常样本少&#xff0c;一般采用无监督方法&#xff0c;在训练过程中只使用正常样本。 解决工业异常检…

ROC、TPR、FPR的含义

1、ROC&#xff08;Receiver Operating Characteristic&#xff09; ROC&#xff08;Receiver Operating Characteristic&#xff09;曲线是一种用于评估分类模型性能的工具。它通过绘制真阳性率&#xff08;True Positive Rate, TPR&#xff09;与假阳性率&#xff08;False…

uni-app - - - - - 实现锚点定位和滚动监听功能(滚动监听功能暂未添加,待后续更新)

实现锚点定位和滚动监听功能 1. 思路解析2. 代码示例 效果截图示例&#xff1a; 点击左侧menu&#xff0c;右侧列表数据实现锚点定位 1. 思路解析 点击左侧按钮&#xff0c;更新右侧scroll-view对应的scroll-into-view的值&#xff0c;即可实现右侧锚点定位滚动右侧区域&am…

Chroma 向量数据入门

Chroma 是 AI 原生的开源矢量数据库。Chroma 使知识、事实和技能可插入 LLM&#xff0c;从而可以轻松构建 LLM 应用程序。Chroma 是 AI 原生的开源矢量数据库。Chroma 使知识、事实和技能可插入 LLM&#xff0c;从而可以轻松构建 LLM 应用程序。 &#x1f31f;Chroma是一个文档…

简单的mybatis batch插入批处理

简单的mybatis batch插入批处理 1.需求 公司的权限管理功能有一个岗位关联资源的分配操作&#xff0c;如果新增一个岗位&#xff0c;有时候需要将资源全部挂上去&#xff0c;原有的是for循环插入资源信息&#xff0c;发现有时候执行速度过慢&#xff0c;所以此处想修改为批处…

Spring Cloud Gateway 之动态uri 自定义过滤器

背景&#xff1a;第三方公司 请求本公司入参和出参一样的同一个接口&#xff0c;根据业务类型不一样需要不同业务微服务处理 &#xff0c;和第三方公司协商在请求头中加入业务类型方便我公司在网关成分发请求。 1&#xff1a;在spring cloud gateway yml 中加入路由 重点是 -…

数据结构之搜索二叉树

目录 一、什么是搜索二叉树 基本概念 特点 注意事项 二、搜索二叉树的C实现 2.0 构造与析构 2.1 插入 2.2 查找 2.3 删除 2.3.1 无牵无挂型 2.3.2 独生子女型 2.3.3 儿女双全型 三、搜索二叉树的应用 3.1 key搜索 3.2 key/value搜索 一、什么是搜索二叉树 搜索二…

数值计算 --- 平方根倒数快速算法(中)

平方根倒数快速算法(中) --- 向Greg Walsh致敬&#xff01; 在前面的介绍中&#xff0c;我们已经知道了这段代码的作者Greg Walsh在函数的最后使用了NR-iteration&#xff0c;且只用了一次NR-iteration就能达到比较理想的精度。这样一来&#xff0c;选择正确的初值就显得尤为重…

云原生|浅谈云原生中的对象存储之MinIO 的使用

一、什么是对象储存 对象存储&#xff08;Object Storage&#xff09;以对象的形式存储和管理数据&#xff0c;这些对象可以是任何类型的数据&#xff0c;例如 PDF&#xff0c;视频&#xff0c;音频&#xff0c;文本或其他文件类型。对象存储使用分布式存储架构&#xff0c;数据…

C语言贪吃蛇小游戏演示和说明

C语言贪吃蛇小游戏演示和说明 设计贪吃蛇游戏的主要目的是让大家夯实C语言基础&#xff0c;训练编程思维&#xff0c;培养解决问题的思路&#xff0c;领略多姿多彩的C语言。 游戏开始后&#xff0c;会在中间位置出现一条只有三个节点的贪吃蛇&#xff0c;并随机出现一个食物&am…

数据结构练习题————(二叉树)——考前必备合集!

今天在牛客网和力扣上带来了数据结构中二叉树的进阶练习题 1.二叉搜索树与双向链表———二叉搜索树与双向链表_牛客题霸_牛客网 (nowcoder.com) 2.二叉树遍历————二叉树遍历_牛客题霸_牛客网 (nowcoder.com) 3.二叉树的层序遍历————102. 二叉树的层序遍历 - 力扣&am…

寿司检测系统源码分享

寿司检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vision …

一文了解高速工业相机

超高速相机是工业相机的一种&#xff0c;一般高速相机指的是数字工业相机&#xff0c;其一般安装在机器流水线上代替人眼来做测量和判断&#xff0c;通过数字图像摄取目标转换成图像信号&#xff0c;传送给专用的图像处理系统。 超高速工业相机的采集速率> 50Gb/s&#xff…

window系统DockerDesktop 部署windows容器

目录 参考文献1、安装Docker Desktop1.1 下载安装包1.2 安装教程1.3 异常解决 2、安装windows容器2.1 先启动DockerDesktop 软件界面2.2 检查docker版本2.3 拉取windows镜像2.4 网盘下载windows镜像 参考文献 windows容器docker中文官网 Docker: windows下跑windows镜像 1、安…

软件测试标准流程(思维导图版)

一套标准的流程在实际工作落地并执行起来&#xff0c;针对管理可起到很好的作用。 针对效率可在工作中不断的执行&#xff0c;执行后不断的进行优化&#xff0c;再次执行&#xff0c;在不断的工作实践中慢慢完善最终适用于整个团队。 这就是标准流程的作用与实际的好处&#…

华为申请鸿蒙甄选、鸿蒙优选商标,加词的注意!

近日华为在35类广告销售上申请鸿蒙智选、鸿蒙优选、鸿蒙精品&#xff0c;鸿蒙甄选等商标&#xff0c;后面所加的词智选、优选、精品、甄选等基本上是属于通用词。 这样在35类拿到鸿蒙通用词商标&#xff0c;需要先拿到“鸿蒙“商标&#xff0c;经普推知产商标老杨检索发现&…

【Linux】yum、vim、gcc使用(超详细)

目录 yum 安装软件 卸载软件 查看安装包 安装一下好玩的命令 vim vim基本操作 模式切换 命令集 vim批量注释 vim配置 gcc 函数库 小知识点&#xff1a; Linux中常见的软件安装方式 --------- 下载&&安装 a、yum/apt b、rpm安装包安装 c、源码安装 y…

周家庄智慧旅游小程序

项目概述 周家庄智慧旅游小程序将通过数字化手段提升游客的旅游体验&#xff0c;依托周家庄的自然与文化资源&#xff0c;打造智慧旅游新模式。该小程序将结合虚拟现实&#xff08;VR&#xff09;、增强现实&#xff08;AR&#xff09;和人工智能等技术&#xff0c;提供丰富的…