队列详解

news2024/12/27 8:11:19

目录

  • 队列
    • 队列的概念及结构
    • 队列的实现
      • 代码
    • 队列功能的实现
      • 队列的尾插void QueuePush(Queue*pq, QDataType x);
        • 结构体封装指针typedef struct Queue
          • 总结
        • 代码
      • 队列的头删void QueuePop(Queue* pq)
        • 代码
      • 队列的初始化void QueueInit(Queue* pq)
        • 代码
      • 队列的销毁void QueueDestroy(Queue* pq, QDataType x)
        • 代码
      • 取队尾数据QDataType QueueBack(Queue* pq)
        • 代码
      • 取队头数据QDataType QueueFront(Queue* pq)
        • 代码
      • 判断队列是否为空bool QueueEmpty(Queue* pq)
        • 代码
      • 获得队列的长度int QueueSize(Queue* pq)
        • 代码

队列

队列的概念及结构

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) (一端入一端出)

入队列:进行插入操作的一端称为队尾
出队列:进行删除操作的一端称为队头

在这里插入图片描述
队列的入队顺序和出队顺序是否和栈一样存在一对多的关系?
因为栈是后进先出,假设我们入栈一个数据A,在A入栈后不继续加入其他的数据B C D,那么如果我们进行出栈的话,数据A就会第一个出来

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
所以栈的入栈顺序和出栈顺序是一对多的情况,举个例子
栈的入栈顺序为A B C D E
则出栈顺序可能为 E D C B A,或者 A B C D E
对于E D C B A这种情况就是当数据全部入栈后,我们按照后进先出的规则,进行出栈,也就是E最后入栈,所以第一个出栈,D是倒数第二个入栈,所以出栈的时候就是第二个…

对于A B C D E这种情况就是当A刚入栈后,我们就让A直接出栈,因为其他的数据B C D E都还没有入栈,所以我们只能让A先出栈,之后再将B入栈,然后B再出栈…
出栈的顺序不止这两种,所以就不一一举例了,总之栈的出栈顺序和入栈顺序是一对多的关系

对于队列而言,因为是先进先出的顺序,所以入和出都只有一种情况,没有一对多的关系

队列的实现

队列也可以数组和链表的结构实现

如果用数组实现的就比较麻烦,因为队列是队尾入,对头出,那么如果用数组去实现队列,我们就要让数组头删,头删的复杂度为O(N)

如果用单链表的话,就很方便,因为是队尾入,队头出,删除数据不像栈一样要尾删,队列只需要让队头的数据删除就可以了,单链表的头删时间复杂度为O(1),并且实现起来要比双向链表要容易些,所以选择用单链表实现队列

单链表实现队列我们可以用带哨兵位的方式,也可以选择不用,带哨兵位需要malloc,最后还需要free掉哨兵位,并且哨兵位在这里的作用不是很大,所以队列的实现我们选择不带哨兵位的方式

实际中我们有时还会使用一种队列叫循环队列,环形队列可以使用数组实现,也可以使用循环链表实现

代码

typedef struct QueueNode
{
	QDataType val;
	struct QueueNode* next;
}QNode;

队列功能的实现

队列的尾插void QueuePush(Queue*pq, QDataType x);

队列尾插函数如果只传两个参数参数头节点的地址,还有需要插入的数据x,(void QueuePush(QNode* * phead, QDataType x)),那么尾插的时间复杂度就为O(N),这样好像单链表就没什么优势了
如果我们传入三个参数void QueuePush(QNode* * phead, QNode* * ptail, QDataType x),其中ptail为指向尾节点的地址,虽然这样可以解决问题,但是我们要注意这里的指针全是二级指针,phead是plist指针传入的参数,因为plist是一个一级指针,要更改一级指针我们就需要将传参类型变成二级指针,ptail也是,非常麻烦

结构体封装指针typedef struct Queue

所以我们要创建一个结构体,将两个指针封装起来, 这样我们传入的参数就不用二级指针,只需要修改结构体成员就可以了

typedef struct Queue
{
	QNode* phead;
	QNode* ptail;
	int size//size为队尾到队头总共有多少个节点
}Queue;
总结

如果遇到函数参数需要传入多个二级指针,那么我们可以用结构体将他们封装起来,结构体封装的成员就是二级指针的值,然后通过结构体访问成员将他们修改,并且在传参时我们只需要传入结构体的地址即可

代码
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QNode* newnode = (QNode * )malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return;
	}
	newnode->val = x;
	newnode->next = NULL;
	if (pq->ptail == NULL)
	{
		pq->ptail = pq->phead = newnode;
	}
	else
	{
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}
	pq->size++;
}

当ptail=NULL的时候就说明没有尾节点,只要队列有一个节点,那么尾节点都不可能为空,尾节点为空说明队列是空的,那么尾插就直接让尾节点=头节点=插入的newnode
如果尾节点不为空,那就直接让尾节点的next=newnode,然后插入newnode后newnode又是新的尾节点,所以让ptail=newnode
最后不要忘记size++

队列的头删void QueuePop(Queue* pq)

头删一般都得考虑两种情况,一种是只有一个节点,另一种就是没有节点

当没有节点时,我们assert断言就可以了

只有一个节点时,在头删后要小心ptail变成野指针,当phead走到下一个节点,发现是空后,如果直接把之前的头节点删除,我们会发现ptail还指向原来头节点的位置,free掉头节点后,ptail就成了野指针
在这里插入图片描述
在这里插入图片描述
所以需要判断如果phead走到下一个节点为空后,要让ptail赋值成NULL

代码
void QueuePop(Queue* pq)
{
	assert(pq);//结构体不能为空
	assert(pq->phead);//判断头节点为空的情况
	QNode* del = pq->phead;//del保存头节点方便后面释放空间
	pq->phead = pq->phead->next;
	free(del);
	if (pq->phead == NULL)
		pq->ptail == NULL;
		pq->size--
}

队列的初始化void QueueInit(Queue* pq)

代码
void QueueInit(Queue* pq)
{
	assert(pq);
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}

队列的销毁void QueueDestroy(Queue* pq, QDataType x)

代码
void QueueDestroy(Queue* pq, QDataType x)
{
	assert(pq);
	QNode* cur = pq->phead;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->phead = pq->ptail = NULL;
	size=0}

取队尾数据QDataType QueueBack(Queue* pq)

代码
QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(pq->ptail);
	return pq->ptail->val;
}

取队头数据QDataType QueueFront(Queue* pq)

代码
QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(pq->phead);
	return pq->phead->val;
}

判断队列是否为空bool QueueEmpty(Queue* pq)

代码
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->phead == NULL;
}

获得队列的长度int QueueSize(Queue* pq)

代码
int QueueSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}

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

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

相关文章

ViT模型复现项目实战

项目源码获取方式见文章末尾! 600多个深度学习项目资料,快来加入社群一起学习吧。 《------往期经典推荐------》 项目名称 1.【基于CNN-RNN的影像报告生成】 2.【卫星图像道路检测DeepLabV3Plus模型】 3.【GAN模型实现二次元头像生成】 4.【CNN模型实现…

是时候用开源降低AI落地门槛了

过去三十多年,从Linux到KVM,从OpenStack到Kubernetes,IT领域众多关键技术都来自开源。开源技术不仅大幅降低了IT成本,也降低了企业技术创新的门槛。 那么,在生成式AI时代,开源能够为AI带来什么?…

【C++打怪之路Lv13】- “继承“篇

🌈 个人主页:白子寰 🔥 分类专栏:重生之我在学Linux,C打怪之路,python从入门到精通,数据结构,C语言,C语言题集👈 希望得到您的订阅和支持~ 💡 坚持…

数据特征工程:如何计算Teager能量算子(TEO)? | 基于SQL实现

目录 0 TKEO能量算子 1 数据准备 2 特征求解 3 小结 0 TKEO能量算子 TEO(Teager能量算子),由Kaiser于1990年代提出的非线性分析方法(参见Kaiser, 1990; 1993),是一种有效的非线性信号处理工具,它能即时反映信号能量的变化。通过计算相邻采样点的值,TEO能够迅速跟…

淘宝/天猫探店大冒险:用taobao.item_search_shop API把宝贝一网打尽

想象一下,你是一位勇敢的探险家,手拿藏宝图(店铺ID),准备潜入神秘的淘宝/天猫店铺,寻找那些隐藏在角落里的宝贝。今天,我们要用taobao.item_search_shop API这张神奇的藏宝图,带你走…

D60【python 接口自动化学习】- python基础之数据库

day60 数据库定义 学习日期:20241106 学习目标:MySQL数据库-- 128:数据库定义 学习笔记: 无处不在的数据库 数据库如何存储数据 数据库管理系统(数据库软件) 数据库和SQL的关系 总结 数据库就是指数据…

2024年最佳解压软件推荐:轻松管理压缩文件的必备工具

在当今数字化时代,文件的传输和存储变得日益频繁,解压软件在文件管理中扮演着至关重要的角色。 随着数据量的不断增长,大文件的压缩和解压需求也越来越高。解压软件能够将大容量的文件压缩成较小的体积,便于存储和传输&#xff0…

Kubernetes的基本构建块和最小可调度单元pod-0

文章目录 一,什么是pod1.1pod在k8s中使用方法(1)使用方法一(2)使用方法二 1.2pod中容器的进程1.3pod的网络隔离管理(1)pause容器的作用 1.4 Pod分类:(1)自主式…

vue实现天地图电子围栏

一、文档 vue3 javascript WGS84、GCj02相互转换 天地图官方文档 注册登录然后申请应用key&#xff0c;通过CDN引入 <script src"http://api.tianditu.gov.cn/api?v4.0&tk您的密钥" type"text/javascript"></script>二、分析 所谓电子围…

QT 实现绘制汽车仪表盘

1.界面实现效果 以下是具体的项目需要用到的效果展示,通常需要使用QPainter类来绘制各种图形和文本,包括一个圆形的仪表盘、刻度、指针和数字。 2.简介 分为以下几个部分,首先设置抗锯齿 painter.setRenderHint(QPainter::Antialiasing)。 QPainter p(this);p.setRender…

【网络】传输层协议TCP(下)

目录 四次挥手状态变化 流量控制 PSH标记位 URG标记位 滑动窗口 快重传 拥塞控制 延迟应答 mtu TCP异常情况 四次挥手状态变化 之前我们讲了四次挥手的具体过程以及为什么要进行四次挥手&#xff0c;下面是四次挥手的状态变化 那么我们下面可以来验证一下CLOSE_WAIT这…

阿里云docker安装禅道记录

docker network ls docker network create -d bridge cl_network sudo docker run --name zentao --restart always -p 9982:80 --networkcl_network -v /data/zentao:/data -e MYSQL_INTERNALtrue -d hub.zentao.net/app/zentao:18.5 升级禅道 推荐用按照此文档升级&a…

迈入国际舞台,AORO M8防爆手机获国际IECEx、欧盟ATEX防爆认证

近日&#xff0c;深圳市遨游通讯设备有限公司&#xff08;以下简称“遨游通讯”&#xff09;旗下5G防爆手机——AORO M8&#xff0c;通过了CSA集团的严格测试和评估&#xff0c;荣获国际IECEx及欧盟ATEX防爆认证证书。2024年11月5日&#xff0c;CSA集团和遨游通讯双方领导在遨游…

Win11家庭版 配置 WSL/Ubuntu+Docker详细步骤

最近换了台工作电脑&#xff0c;Windows系统的&#xff0c;想发挥下显卡的AI算算力&#xff0c;所以准备搞下docker环境&#xff0c;下面开始详细介绍&#xff1a; 1、准备系统 最开始是想安装Windows Docker Desktop的&#xff0c;奈何网络问题&#xff0c;死活不能下载镜像…

apache poi 实现下拉框联动校验

apache poi 提供了 DataValidation​ 接口 让我们可以轻松实现 Excel 下拉框数据局校验。但是下拉框联动校验是无法直接通过 DataValidation ​实现&#xff0c;所以我们可以通过其他方式间接实现。 ‍ 步骤如下&#xff1a; 创建一个隐藏 sheet private static void create…

LabVIEW扫描探针显微镜系统

开发了一套基于LabVIEW软件开发的扫描探针显微镜系统。该系统专为微观尺度材料的热性能测量而设计&#xff0c;特别适用于纳米材料如石墨烯、碳纳米管等的研究。系统通过LabVIEW编程实现高精度的表面形貌和热性能测量&#xff0c;广泛应用于科研和工业领域。 项目背景 随着纳…

【Python】强大的正则表达式工具:re模块详解与应用

强大的正则表达式工具&#xff1a;re模块详解与应用 在编程和数据处理中&#xff0c;字符串的处理是不可避免的一项任务。无论是从文本中提取信息、验证数据格式&#xff0c;还是进行复杂的替换操作&#xff0c;正则表达式&#xff08;Regular Expression&#xff0c;简称Rege…

Redis数据库测试和缓存穿透、雪崩、击穿

Redis数据库测试实验 实验要求 1.新建一张user表&#xff0c;在表内插入10000条数据。 2.①通过jdbc查询这10000条数据&#xff0c;记录查询时间。 ②通过redis查询这10000条数据&#xff0c;记录查询时间。 3.①再次查询这一万条数据&#xff0c;要求根据年龄进行排序&#…

今天要重新认识下注解@RequestBody

在Spring框架中&#xff0c;RequestBody是一个常用的注解&#xff0c;它用于将HTTP请求体中的数据绑定到控制器&#xff08;Controller&#xff09;处理方法的参数上。这个注解通常与RESTful Web服务一起使用&#xff0c;在处理POST或PUT请求时尤为常见&#xff0c;因为这些请求…

在vscode中如何利用git 查看某一个文件的提交记录

在 Visual Studio Code (VSCode) 中&#xff0c;你可以使用内置的 Git 集成来查看某个文件的提交历史。以下是具体步骤&#xff1a; 使用 VSCode 内置 Git 功能 打开项目&#xff1a; 打开你的项目文件夹&#xff0c;确保该项目已经是一个 Git 仓库&#xff08;即项目根目录下…