数据结构 - 队列
队列也是一种操作受限的线性数据结构,与栈很相似。

01定义
栈的操作受限表现为只允许在队列的一端进行元素插入操作,在队列的另一端只允许删除操作。这一特性可以总结为先进先出(First In First Out,简称FIFO)。这意味着在队列中第一个加入的元素将第一个被移除。

入****队:向队列中添加新元素的行为叫做入队;
出****队:从队列中移除元素的行为叫做出队;
队头:在队列中允许进行元素移除行为的一端称为队头;
队尾:在队列中运行进行元素添加行为的一端称为队尾;
空****队列:当队列中没有元素时称为空队列。
满****队列:当队列是有限容量,并且容量已用完,则称为满队列。
队列****容量:当队列是有限容量,队列容量表示队列可以容纳的最大元素数量。
队列****大小:表示当前队列中的元素数量。

02分类
队列根据存储方式和功能特性有两种分类方式。
1、根据存储方式分类
队列是逻辑结构,因此以存储方式的不同可以分为顺序队列和链式队列。
顺序队列就是所有的队列元素都存储在连续的地址空间中,因此可以通过数组来实现顺序队列,因为数组的特性也导致顺序队列容量是固定的,不易扩容,这也导致容易浪费空间,同时还要注意元素溢出等问题。
链式队列顾名思义就是采用链式方式存储,可以通过链表实现,因此链式队列可以做到无限扩容,大大的提高了内存利用率。

2、根据功能特性分类
根据功能特性可以分类出很多专有队列,下面我们列举几个简单介绍一下。
阻塞队列:当空队列时会阻塞出队操作,当满队列时会阻塞入队操作。
优先队列:队列中每个元素都有一个优先级别属性,而元素的出队操作取决于这个优先级别属性,即优先级别高则优先出队。
延迟队列:队列中每个元素都标记一个时间记录,元素只有在指定的延时时间后才会触发出队操作。
循环队列:当使用数组实现队列时,可以通过把队头和队尾相连接,即当队尾到达数组的尾端可以“绕回”数组的开头,通过这种巧妙的设计来提高数组空间利用率。
双端队列:是一种两端都可以进行入队和出队操作的数据结构。
根据这些队列特性,在不同的场景中可以起到意想不到的效果。
下面我们将顺序队列和链式队列的实现进行详细讲解。
03实现(顺序队列)
下面我们借助数组来实现顺序队列,其核心思想是把数组的起始位置作为队头,把数组尾方向作为队尾。当发生出队行为时,需要把剩余所有数据向队头方向移动一位,为什么要做这步操作呢?
首先顺序队列内部是数组,假设数组内可以存放7个元素,此时数组已存满,因此不可以再进行添加新元素入队操作了,然后我们对数组头元素进行出队操作,此时数组因为出队会留下一个空位,如下图。

那么此时是否可以进行入队操作呢?直接告诉我们应该可以,因为数组头已经有空位了。但是我们约定了队列只能从数组尾进行入队操作,而此时数组尾并没有空位提供给新入队的元素,因此实际上无法进行入队操作。
那要如何处理呢?最简单的方法就是当发生出队操作时,后面所有的元素都向着队头方向移动一位,把队尾空出一位,这每出一个元素就可以入一个元素。

当然这也不是唯一方案,还是通过循环队列解决这一问题,有兴趣的可以研究一下。
1、ADT定义
我们首先来定义顺序队列的ADT。
ADT Queue{
数据对象:D 是一个非空的元素集合,D = {a1, a2, ..., an},其中 ai 表示队列中的第i个元素,n是队列的长度。数据关系:D中的元素通过它们的索引(位置)进行组织,索引是从0到n-1的整数,并且遵循元素先进先出的原则。基本操作:[Init(n) :初始化一个指定容量的空队列。Capacity:返回队列容量。Length:返回队列长度。Head:返回队头元素,当为空队列则报异常。Tail:返回队尾元素,当为空队列则报异常。IsEmpty():返回是否为空队列。IsFull():返回是否为满队列。Enqueue():入队即添加元素,当为满队列则报异常。Dequeue():出队即返回队头元素并把其从队列中移除,当为空队列则报异常。
]
}
定义好队列ADT,下面我们就可以开始自己实现的队列。
2、初始化 Init
首先定义3个变量用于存放队列元素数组、队列容量以及队尾索引,而没有定义队头索引是因为队头索引永远等于0。
初始化结构主要做几件事。
-
初始化队列的容量;
-
初始化存放队列元素数组;
-
初始化队尾索引;
具体实现代码如下:
//存放队列元素
private T[] _array;
//队列容量
private int _capacity;
//队尾索引,为-1表示空队列
private int _tail;
//初始化队列为指定容量
public MyselfQueueArray<T> Init(int capacity)
{//初始化队列容量为capacity_capacity = capacity;//初始化指定长度数组用于存放队列元素_array = new T[_capacity];_tail = -1;//返回队列return this;
}
3、获取队列容量 Capacity
这个比较简单直接把队列容量私有字段返回即可。
//队列容量
public int Capacity
{get{return _capacity;}
}
4、获取队列长度 Length
我们并没有定义队列长度的私有字段,因为队尾索引即表示数组最后一个元素索引,即可以代表队列长度,因此只需用队尾索引加1即可得到队列长度,同时需要注意判断队列是否为空,如果为空则报错。
//队列长度
public int Length
{get{if (IsEmpty()){return 0;}//队列长度等于队尾索引加1return _tail + 1;}
}
5、获取队头元素 Head
基于我们上面的约定,队头元素永远对应数组的第一个元素,因此可以直接获取索引为0的数组元素。空队列则报错。具体代码如下:
//获取队头元素
public T Head
{get{if (IsEmpty()){//空队列,不可以进行获取队头元素操作throw new InvalidOperationException("空队列");}return _array[0];}
}
6、获取队尾元素 Tail
因为我们定义了队尾索引私有变量,因此可以直接通过队尾索引获取。具体代码如下:
//获取队尾元素
public T Tail
{get{if (IsEmpty()){//空队列,不可以进行获取队头元素操作throw new InvalidOperationException("空队列");}return _array[_tail];}
}
7、获取是否空队列 IsEmpty
是否空队列只需判断队尾索引是否小于0即可。
//是否空队列public bool IsEmpty(){//队尾索引小于0表示空队列return _tail < 0;}
8、获取是否满队列 IsFull
是否满队列只需判断队尾索引是否与队列容量减1相等,代码如下:
//是否满队列
public bool IsFull()
{//队头索引等于容量大小减1表示满队列return _tail == _capacity - 1;
}
9、入队 Enqueue
入队只需向队列内部数组尾添加一个新元素即可,因此先把队尾索引先后移动一位,然后再把新元素赋值给队尾元素,同时还需要检查是否为满队列,如果是满队列则报错,具体实现代码如下:
//入队
public void Enqueue(T value)
{if (IsFull()){//满队列,不可以进行入队列操作throw new InvalidOperationException("满队列");}//队尾索引向后移动1位_tail++;//给队尾元素赋值新值_array[_tail] = value;
}
10、出队 Dequeue
出队则大致分为以下几步:
-
判断是否为空队列,空队列则报错;
-
取出队头元素暂存,重置队头元素为默认值;
-
把队头后面所有元素向队头方向移动一位;
-
重置队尾元素为默认值;
-
队尾索引向队头方向移动一位,即队尾索引减1;
-
返回暂存的队头元素;
具体实现代码如下:
//出队
public T Dequeue()
{if (IsEmpty()){//空队列,不可以进行出队列操作throw new InvalidOperationException("空队列");}//取出队头元素var value = _array[0];//对头元素重置为默认值_array[0] = default;//队头元素后面所有元素都向队头移动一位for (int i = 0; i < _tail; i++){_array[i] = _array[i + 1];}//队尾元素重置为默认值_array[_tail] = default;//队尾索引向队头方向移动一位_tail--;//返回队头元素return value;
}
04实现(链式队列)
我们借助链表来实现链式队列,其核心思想是把链表尾节点作为队尾,把链表首元节点作为队头。
1、ADT定义
相对于顺序队列的ADT来说,链式队列的ADT少了两个方法即获取队列容量和是否满队列,这也是链表特性带来的好处。
2、初始化 Init
首先需要定义链表节点类,包含两个属性数据域和指针域。
然后需要定义3个变量用于存放队头节点、队尾节点以及队列长度。
而初始化结构主要初始化3个变量初始值,具体实现如下:
public class MyselfQueueNode<T>
{//数据域public T Data;//指针域,即下一个节点public MyselfQueueNode<T> Next;public MyselfQueueNode(T data){Data = data;Next = null;}
}
public class MyselfQueueLinkedList<T>
{//队头节点即首元节点private MyselfQueueNode<T> _head;//队尾节点即尾节点private MyselfQueueNode<T> _tail;//队列长度private int _length;//初始化队列public MyselfQueueLinkedList<T> Init(){//初始化队头节点为空_head = null;//初始化队尾节点为空_tail = null;//初始化队列长度为0_length = 0;//返回队列return this;}
}
3、获取队列长度 Length
这个比较简单直接把队列长度私有字段返回即可。
//队列长度
public int Length
{get{return _length;}
}
4、获取队头元素 Head
获取队头元素可以通过队头节点数据域直接返回,但是要注意判断队列是否为空队列,如果为空队列则报异常。具体代码如下:
//获取队头元素
public T Head
{get{if (IsEmpty()){//空队列,不可以进行获取队头元素操作throw new InvalidOperationException("空队列");}//返回队头节点数据域return _head.Data;}
}
5、获取队尾元素 Tail
获取队尾元素可以通过队尾节点数据域直接返回,但是要注意空栈则报异常。具体代码如下:
//获取队尾元素
public T Tail
{get{if (IsEmpty()){//空队列,不可以进行获取队尾元素操作throw new InvalidOperationException("空队列");}//返回队尾节点数据域return _tail.Data;}
}
6、获取是否空队列 IsEmpty
是否空队列只需判断队头节点和队尾节点是否都为空即可。
//是否空队列
public bool IsEmpty()
{//队头节点为null和队尾节点都为空表示空队列return _head == null && _tail == null;
}
7、入队 Enqueue
入队大致分为以下几步:
-
需要先创建一个新节点;
-
如果原队尾节点不为空,则把原队尾节点指针域指向新节点;
-
把原队尾节点更新为新节点;
-
如果队头节点为空,则说明这是第一个元素,所以队头和队尾都是同一个节点,因此要把队尾节点赋值给队头节点;
-
队列长度加1;
具体实现代码如下:
//入队
public void Enqueue(T value)
{//创建新的队尾节点var node = new MyselfQueueNode<T>(value);//如果队尾节点不为空,则把新的队尾节点连接到尾节点后面if (_tail != null){_tail.Next = node;}//队尾节点变更为新的队尾节点_tail = node;//如果队头节点为空,则为其赋值为队尾节点if (_head == null){_head = _tail;}//队列长度加1_length++;
}
8、出队 Dequeue
出队则大致分为以下几步:
-
判断是否空队列,空队列则报错;
-
获取队头节点数据域暂存;
-
更新头节点为原队头节点对应的下一个节点;
-
如果队头节点为空,则说明为空队列,队尾节点也要置空;
-
队列长度减1;
-
返回暂存的队头节点数据;
具体实现代码如下:
//出队
public T Dequeue()
{if (IsEmpty()){//空队列,不可以进行出队列操作throw new InvalidOperationException("空队列");}//获取队头节点数据var data = _head.Data;//把队头节点变更为原队头节点对应的下一个节点_head = _head.Next;//如果队列为空,表明为空队列,同时更新队尾为空if (_head == null){_tail = null; }//队列长度减1_length--;//返回队头节点数据return data;
}
注:测试方法代码以及示例源码都已经上传至代码库,有兴趣的可以看看。https://gitee.com/hugogoos/Planner
相关文章:
数据结构 - 队列
队列也是一种操作受限的线性数据结构,与栈很相似。 01定义 栈的操作受限表现为只允许在队列的一端进行元素插入操作,在队列的另一端只允许删除操作。这一特性可以总结为先进先出(First In First Out,简称FIFO)。这意味…...
基于springboot美食推荐商城的设计与实现
基于springboot美食推荐商城的设计与实现 开发语言:Java 框架:springboot JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7 数据库工具:Navicat11 开发软件:idea 源码获取:https:…...
React开发一个WebSocket
export default class SocketService {static instance null;static get Instance() {if (!this.instance) {this.instance new SocketService();}return this.instance;}// 和服务端连接的socket对象ws null;// 存储回调函数callBackMapping {};// 标识是否连接成功connec…...
Oracle DECODE 丢失时间精度的原因与解决方案
在Oracle数据库中,DECODE 函数是一个非常实用的条件处理函数,通常用于替代简单的 CASE WHEN 语句。它根据给定的值列表进行匹配,如果匹配成功则返回相应的值。如果不匹配,返回一个默认值。 问题描述 SELECT DECODE(-21, -1, NU…...
如何用示波器检测次级点火系统(一)
写在最前面: 单看标题可能会让你觉得这篇文章的主题是关于检测线圈,火花塞和火花塞插头电线。但我们指的是分析燃烧室内电子的行为。目标是看燃料混合物,阀座,压缩,积碳和其它影响这种特性的症状。最终目的是要学会分…...
基于SpringBoot+Vue+uniapp的涪陵区特色农产品交易系统的详细设计和实现(源码+lw+部署文档+讲解等)
详细视频演示 请联系我获取更详细的视频演示 项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念,提供了一套默认的配置,让开发者可以更专注于业务逻辑而不…...
bmp怎么转换为jpg?快速批量将bmp转换为jpg
bmp怎么转换为jpg?在日常的数字生活中,我们时常会遇到各种格式的图片文件,它们各自拥有不同的特点和用途。最近,我遇到了一个有趣的小插曲:我从网络上下载了一张精美的BMP格式图片,打算用它作为一篇报告的背…...
centos8配置java环境变量jdk8u422-b05
1. 下载 JDK 8u422-b05 首先,确保已经下载了 JDK 8u422-b05 的二进制文件。如果还没有下载,你可以去 Oracle 官方网站或者其他可信的源下载 JDK 8u422。 2. 安装 JDK 将下载的 JDK 文件解压到 /usr/local/java 目录下: sudo mkdir /usr/l…...
基于SSM的校园拓展活动管理系统
文未可获取一份本项目的java源码和数据库参考。 1 选题背景 校园文化是精神的载体,是青年成长成才的沃土,是一种体现校园的硬件设施、精神风貌、制度体系、办学理念以及办学特色的综合文化。文明程度高、文化气息浓、活动种类多的校园文化不仅能焕发学校…...
Python随机森林算法详解与案例实现
目录 Python随机森林算法详解与案例实现1、随机森林算法概述2、随机森林的原理3、实现步骤4、分类案例:使用随机森林预测鸢尾花品种4.1 数据集介绍4.2 代码实现4.3 代码解释4.4 运行结果 5、回归案例:使用随机森林预测波士顿房价5.1 数据集介绍5.2 代码实…...
提示词高级阶段学习day2.1-在提示词编写中对{}的使用教程
首先在 prompt engineering 中,使用 {} 通常是为了标识占位符或变量, 这些占位符可以在实际生成内容时被动态替换。 通过这种方式,prompt 可以更加通用和灵活,适用于不同的输入数据场景。 以下是一个体系化、结构化的教程&…...
2024年,每一个大模型都躲不过容嬷嬷和紫薇
2024年还不上视频生成的大模型公司,还能上桌吃饭吗? 连最积极搞AI的李彦宏,在这件事上也迟疑了。 “百度不碰Sora类的视频生成方向。”李彦宏在近期的2024年Q3总监会上说道。原因在于,10年、20年都可能难以商业化应用。 从Open…...
SpringBoot之RedisTemplate基本配置
公司要求redis配置密码使用密文,但是程序使用的是spring默认的redisTemplate,那么就需要修改配置实现密码加解密。 先搞个加密工具类: public class SM2Encryptor {// 加密,使用公钥public static String encryptText(String pub…...
SparseRCNN 模型,用于目标检测任务
SparseRCNN 模型,用于目标检测任务 import logging import math from typing import Listimport numpy as np import torch import torch.distributed as dist import torch.nn.functional as F from torch import nn #项目完整代码下载链接:https://download.csdn.net/downl…...
【AIGC】第一性原理下的ChatGPT提示词Prompt设计:系统信息与用户信息的深度融合
博客主页: [小ᶻZ࿆] 本文专栏: AIGC | ChatGPT 文章目录 💯前言💯第一性原理与ChatGPT提示词Prompt设计应用第一性原理于ChatGPT提示词Prompt设计系统信息和用户信息的融合实际应用结论 💯系统信息与用户信息的定义和重要性系…...
DeepSpeed性能调优与常见问题解决方案
1. 引言 什么是DeepSpeed? DeepSpeed是由微软开源的深度学习训练优化库,旨在帮助研究人员和工程师高效地训练大规模深度学习模型。基于PyTorch框架,DeepSpeed提供了一系列先进的技术,如ZeRO(Zero Redundancy Optimiz…...
【GESP】C++一级练习BCQM3052,鸡兔同笼
GESP一级知识点:for循环和if的应用。 题目题解详见:https://www.coderli.com/gesp-1-bcqm3052/ 【GESP】C一级练习BCQM3052,鸡兔同笼 | OneCoderGESP一级知识点:for循环和if的应用。https://www.coderli.com/gesp-1-bcqm3052/ …...
Android面试之5个性能优化相关的深度面试题
本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”,和我一起每天进步一点点 面试题目1:如何优化Android应用的启动速度? 解答: 优化Android应用的启动速度可以从以下几个方面入手: 1、 减少主线程工…...
R语言机器学习算法实战系列(六)K-邻近算法 (K-Nearest Neighbors)
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍教程下载数据加载R包导入数据数据预处理数据描述数据切割调节参数构建模型预测测试数据评估模型模型准确性混淆矩阵模型评估指标ROC CurvePRC Curve保存模型总结系统信息介绍 K-邻…...
FPGA图像处理之构建3×3矩阵
免责声明:本文所提供的信息和内容仅供参考。作者对本文内容的准确性、完整性、及时性或适用性不作任何明示或暗示的保证。在任何情况下,作者不对因使用本文内容而导致的任何直接或间接损失承担责任,包括但不限于数据丢失、业务中断或其他经济…...
SpringBoot-17-MyBatis动态SQL标签之常用标签
文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...
使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...
【Oracle APEX开发小技巧12】
有如下需求: 有一个问题反馈页面,要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据,方便管理员及时处理反馈。 我的方法:直接将逻辑写在SQL中,这样可以直接在页面展示 完整代码: SELECTSF.FE…...
如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...
【HTML-16】深入理解HTML中的块元素与行内元素
HTML元素根据其显示特性可以分为两大类:块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...
Spring是如何解决Bean的循环依赖:三级缓存机制
1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间互相持有对方引用,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...
C/C++ 中附加包含目录、附加库目录与附加依赖项详解
在 C/C 编程的编译和链接过程中,附加包含目录、附加库目录和附加依赖项是三个至关重要的设置,它们相互配合,确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中,这些概念容易让人混淆,但深入理解它们的作用和联…...
