数据结构——队列(Queue)
目录
1.队列的介绍
2.队列工程
2.1 队列的定义
2.1.1 数组实现队列
2.1.2 单链表实现队列
2.2 队列的函数接口
2.2.1 队列的初始化
2.2.2 队列的数据插入(入队)
2.2.3 队列的数据删除(出队)
2.2.4 取队头数据
2.2.5 取队尾数据
2.2.6 判断队列是否为空
2.2.7 队列长度统计
2.2.8 队列的销毁
3.队列总结反思
1.队列的介绍
队列,顾名思义,作为有素质的新时代公民,在现实生活中我们常常会遇到排队的场景,而队列就是借此种情形衍生出来的数据结构形式。在需要排队的时候,我们面对一个队列会自觉地站在队尾。随着当队伍中的人慢慢出队,我们的位置也从队尾慢慢移动到了队头,当我们成为一个队的第一个人时,我们就明白终于轮到我们出队了。队列这种数据结构组织数据的形式和排队的场景十分相似,均为先进先出,后进后出的规则。

在掌握了栈这种数据结构的基础之上,我们再来学习队列会比较轻松。栈主要实现的是“先进后出,后进先出”的规则,而队列遵循的则是“先进先出,后进后出”的规律。因此我们可以相互类比地进行学习。
2.队列工程
2.1 队列的定义
在创建队列之前,我们需要考虑队列用什么方式实现。我们依然从数组和链表两种结构去考虑优劣,我们发现队列在出队和访问时需要访问队头,在入队时需要找到队尾,所以我们根据这一特征仔细分析一下队列最合适的实现方式。
2.1.1 数组实现队列
当我们打算用数组实现队列的时候:
如果以下标小的一端为队头,我们发现在入队时,我们很容易可以在队尾插入数据。但是在出队的时候,类似于顺序标的头删操作,所有数据前移一位,需要O(n)的时间复杂度。
如果以下标大的一端为队头,在出队是很容易。但是在入队时同样需要依次挪动数据,也导致了O(n)的时间复杂度。
2.1.2 单链表实现队列
当使用单链表的时候,头删头插数据很容易,但是尾插尾删因为需要遍历链表找尾而变得复杂。这是我们只需要再引入一个指针指向单链表的尾即可解决这个问题。因为将单链表用作队列的时候,队列只会对队头和队尾进行操作,所以无论哪一边为队头,队列实际操作的都只有链表的头结点和尾结点,所以我们只需要定义指针指向头和尾即可避免遍历的冗余操作。
弄明白这一点后,我们再来详细讨论一下到底以单链表的哪一边为队头,哪一边为队尾。
如果以单链表头结点为队头,以尾结点为队尾。在入队的时候我们需要将数据插入队尾,也即在尾结点后插入数据,因为我们提前存储了尾结点位置,所以可以直接将新结点链接在尾结点后。在出队的时候,就相当于删除队头的结点,也就是单链表头删,也没有问题。看来这种方案是个不错的选择。
如果以单链表头结点为队尾,以尾结点为队头。那么在入队的时候,我们需要将数据插入队尾,也就是单链表头插,我们可以做到直接链接。在出队的时候,我们需要删除队头的数据,即单链表尾删,熟悉单链表的小伙伴们都知道,单链表尾删是需要尾结点前一个结点的(需要改变倒数第二个结点的next,使其为空指针),所以在选取这种方式时,我们使用指针指示的就不该是尾结点了,而应该是尾结点的前一个结点。
在这篇博客中,我们采取第一种方式(单链表头结点为队头,以尾结点为队尾)。
typedef int QDataType;typedef struct QueueNode
{QDataType val;struct QueueNode* next;
}QNode;typedef struct Queue
{QNode* phead;QNode* ptail;int size;
}Queue;
首先定义出单链表的结点结构体,然后再定义出队列的结构体,队列结构体之中看似有三个成员,实际上都是对队列载体——单链表的信息描述,分别是链表头结点(队头),链表尾结点(队尾),链表节点个数(队列长度)。
2.2 队列的函数接口
2.2.1 队列的初始化
新建了一个队列后,我们首先需要对其进行初始化,将队列结构体中队头、队尾指针置空,将size置为0。
void QueueInit(Queue* pq)
{assert(pq);pq->phead = pq->ptail = NULL;pq->size = 0;
}
2.2.2 队列的数据插入(入队)
通过我们刚才的分析,入队可以简单的视为尾插,所以我们按照尾插的逻辑来写入队函数即可。
首先需要开辟空间创建新结点,然后熟悉单链表的小伙伴又知道了,在我们链接结点之前需要对特殊情况进行特殊处理。一般而言,单链表的特殊情况就是空链表和只有一个结点的链表。当链表为空时,队列中phead和ptail指针均为空指针,直接链接肯定会出错,所以当为空链表时,需要特殊处理一下。当链表仅有一个结点时,其ptail就是尾结点,所以不需要特殊考虑,和其余情况一样,可以直接链接。
void QueuePush(Queue* pq, QDataType x)
{assert(pq);QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("malloc fail");return;}newnode->next = NULL;newnode->val = x;if (pq->phead == NULL){pq->phead = pq->ptail = newnode;}else{pq->ptail->next = newnode;pq->ptail = newnode;}pq->size++;
}
2.2.3 队列的数据删除(出队)
出队操作在这里就相当于头删。对于删除操作我们要做最基本的判断排除空链表的情况,这里我使用了assert断言。然后考虑特殊情况,当链表只有一个结点时,头删后链表为空,队头指针和队尾指针都需要置空,其余情况都是只需要改变队头指针即可。
void QueuePop(Queue* pq)
{assert(pq);assert(pq->phead);QNode* del = pq->phead;if (pq->phead == pq->ptail){pq->phead = pq->ptail = NULL;}else{pq->phead = pq->phead->next;}free(del);del = NULL;pq->size--;
}
2.2.4 取队头数据
很简单的操作,取出队头指针所指结点的保存的值即可。
QDataType QueueFront(Queue* pq)
{assert(pq);assert(pq->phead);return pq->phead->val;
}
2.2.5 取队尾数据
取队尾数据在某些场景下会被使用,其方法和取队头数据一样。
QDataType QueueBack(Queue* pq)
{assert(pq);assert(pq->ptail);return pq->ptail->val;
}
2.2.6 判断队列是否为空
队列为空的特征很多,包括队头指针、队尾指针为空,队列长度为0,任取一个作为判断依据即可。
bool QueueEmpty(Queue* pq)
{assert(pq);return pq->phead == NULL;
}
2.2.7 队列长度统计
队列的长度由成员size指出,将其作为返回值即可。
int QueueSize(Queue* pq)
{assert(pq);return pq->size;
}
2.2.8 队列的销毁
队列实际上是一个链表+一个记录链表信息的结构体,所以在销毁链表的时候,我们需要按照销毁单链表的方式先释放单链表所占用的空间,然后将记录信息的结构体其中的值置0、指针置空,防止野指针。
void QueueDestroy(Queue* pq)
{assert(pq);QNode* cur = pq->phead;while (cur){QNode* tmp = cur;cur = cur->next;free(tmp);tmp = NULL;}pq->phead = pq->ptail = NULL;pq->size = 0;
}
3.队列总结反思
栈和队列都是比较简单的数据结构,分别采取数组和链表实现了“先进后出,后进先出和“先进先出,后进后出”的功能。只要能熟练的控制应用单链表,我觉得队列应该不在话下。队列在具体实际中的用途也很广泛,在广度优先搜索中队列会作为数据存储方式,对所有出现的情况进行记录与拓展。
相关文章:
数据结构——队列(Queue)
目录 1.队列的介绍 2.队列工程 2.1 队列的定义 2.1.1 数组实现队列 2.1.2 单链表实现队列 2.2 队列的函数接口 2.2.1 队列的初始化 2.2.2 队列的数据插入(入队) 2.2.3 队列的数据删除(出队) 2.2.4 取队头数据 2.2.5 取队…...
uniapp微信小程序投票系统实战 (SpringBoot2+vue3.2+element plus ) -后端架构搭建
锋哥原创的uniapp微信小程序投票系统实战: uniapp微信小程序投票系统实战课程 (SpringBoot2vue3.2element plus ) ( 火爆连载更新中... )_哔哩哔哩_bilibiliuniapp微信小程序投票系统实战课程 (SpringBoot2vue3.2element plus ) ( 火爆连载更新中... )共计21条视频…...
两种方式实现mysql截取年月日
select date_format(now(), %Y-%m-%d) select substring(now(), 1, 10)...
WPF 使用矢量字体图标
矢量字体图标 在WPF项目中经常需要显示图标,但是项目改动后,有时候需要替换和修改图标,这样非常麻烦且消耗开发和美工的时间。为了快速开发项目,节省项目时间,使用图标矢量字体图标是一个非常不错的选择。 矢量字体图标…...
编程语言的语法糖,你了解多少?
什么是语法糖 语法糖是一种编程语言的特性,通常是一些简单的语法结构或函数调用,它可以通过隐藏底层的复杂性,并提供更高级别的抽象,从而使代码更加简洁、易读和易于理解,但它并不会改变代码的执行方式。 为什么需要语…...
MySQL中FLUSH TABLES命令语法
在MySQL中,FLUSH TABLES 命令的作用是刷新表。当你使用 FLUSH TABLES 命令的具体选项时(例如 FLUSH TABLES WITH READ LOCK),该选项必须是在 FLUSH 语句中唯一指定的命令。即,在一个 FLUSH 语句中,你只能使…...
如何在小米4A刷OpenWRT系统并通过cpolar实现公网访问本地路由器
文章目录 前言1. 安装Python和需要的库2. 使用 OpenWRTInvasion 破解路由器3. 备份当前分区并刷入新的Breed4. 安装cpolar内网穿透4.1 注册账号4.2 下载cpolar客户端4.3 登录cpolar web ui管理界面4.4 创建公网地址 5. 固定公网地址访问 前言 OpenWRT是一个高度模块化、高度自…...
Spring学习之——事务控制
Spring中的事务控制 说明: JavaEE体系进行分层开发,事务处理位于业务层,Spring提供了分层设计业务层的事务处理解决方案。 Spring框架为我们提供了一组事务控制的接口。具体在后面的小节介绍。这组接口是在spring-tx.RELEASE.jar中。 spri…...
云原生技术专题 | 解密2023年云原生的安全优化升级,告别高危漏洞、与数据泄露说“再见”(安全管控篇)
背景介绍 2023年,我们见证了科技领域的蓬勃发展,每一次技术革新都为我们带来了广阔的发展前景。作为后端开发者,我们深受其影响,不断迈向未来。 随着数字化浪潮的席卷,各种架构设计理念相互交汇,共同塑造了…...
如何启用Windows电脑的内置Administrator账户
前言 不知道从什么时候开始,新电脑或者新系统开机之后都会出现一个界面让你创建一个账户,但这个账户有可能是本地账户(Windows10)还有强制你登录微软账户的(Windows11)。 好像曾经熟悉的电脑Administrator…...
智慧工厂:科技与制造融合创新之路
随着科技的迅猛发展,智慧工厂成为制造业领域的热门话题。智慧工厂利用先进的技术和智能化系统,以提高生产效率、降低成本、增强产品质量和灵活性为目标,正在引领着未来制造业的发展。 智慧工厂的核心是数字化和自动化生产,相较于传…...
SCADE—产品级安全关键系统的MBD开发套件
产品概述 随着新能源三电、智能驾驶等新技术的应用,汽车中衍生出很多安全关键零部件,如BMS、VCU、MCU、ADAS等,相应的软件在汽车中的比重越来越大,并且安全性、可靠性要求也越来越高。ANSYS主要针对安全关键零部件的嵌入式产品级软…...
PyTorch|保存与加载自己的模型
训练好一个模型之后,我们往往要对其进行保存,除非下次用时想再次训练一遍。 下面以一个简单的回归任务来详细讲解模型的保存和加载。 来看这样一组数据: xtorch.linspace(-1,1,50)xx.view(50,1)yx.pow(2)0.3*torch.rand(50).view(50,1) 画…...
javaScript:Math工具类方法
1 Math工具类方法: >和其他的类的不同,Math并不是一个构造函数,也就是无法通过new来创建Math的实例 >Math表示的数学,在Math对象中存储了一组数学运算相关的常量的和方法 >这些常量和方法可以直接通过Math来访问 >比如Math.P…...
ffmpeg转码新技能
ffmpeg转码新技能 mp3转wavmp4转gif mp3转wav 今天发现之前用ffmpeg转码不好使了。今天发现一个ffmpeg转码新的用法非常简单 ffmpeg -i 0104.mp3 -f wav 0104.wav mp4转gif 同学求助将mp4转gif。我先用剪影把mp4的多余黑边去除。然后用ffmpeg将mp4转出了gif ffmpeg -i shu…...
Docker学习笔记(一):Docker命令总结
Docker命令总结 一、Docker介绍1.1 镜像与容器区别 二、Docker命令 一、Docker介绍 Docker是一个开源的应用容器引擎,它允许开发者在几乎任何环境中运行应用程序,而无需担心运行环境的问题。Docker的核心概念是容器,它可以将应用程序及其依赖…...
JavaWeb——后端案例
五、案例 1. 开发规范—Restful REST(Representational State Transfer),表述性状态转换,是一种软件架构风格 注: REST是风格,是约定方式,不是规定,可以打破描述模块的功能通常使…...
【CSS】浅学一下filter
目录 1、基本概念 2、用法 3、应用案例 更加智能的阴影效果: 元素、网页置灰 元素强调、高亮 毛玻璃效果 调整网页sepia 褐色值可以实现护眼效果 1、基本概念 CSS filter 属性将模糊或颜色偏移等图形效果(对比度、亮度、饱和度、模糊等等&#…...
Commander One for Mac:强大的双窗格文件管理器,让你的工作效率倍增!
Commander One for Mac是一款功能强大的文件管理工具,具有以下主要功能: 双窗格设计:主界面分为两个窗格,用户可以在左侧窗格中导航和浏览文件系统的目录结构,在右侧窗格中查看文件和文件夹的内容。文件操作ÿ…...
leetcode09-机器人能否返回原点
题目链接: https://leetcode.cn/problems/robot-return-to-origin/?envTypestudy-plan-v2&envIdprogramming-skills 思路: 循环遍历,模拟即可 代码: class Solution {public boolean judgeCircle(String moves) {int n m…...
华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...
【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...
【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)
要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况,可以通过以下几种方式模拟或触发: 1. 增加CPU负载 运行大量计算密集型任务,例如: 使用多线程循环执行复杂计算(如数学运算、加密解密等)。运行图…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...
安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...
AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别
【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而,传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案,能够实现大范围覆盖并远程采集数据。尽管具备这些优势…...
