【数据结构】详解队列
现在我们来掌握一下队列!如果有对往期知识有不足地方,可翻阅之前文章哦!
个人主页:小八哥向前冲~-CSDN博客
所属专栏:数据结构【c语言版】_小八哥向前冲~的博客-CSDN博客
栈和队列的实现其实都是对你顺序表和链表的检验,只有一些新的概念罢了!
哈哈!不信就往下看吧!!!
目录
什么是队列?
扩展--循环队列
队列的实现
初始化
队列的插入
队列的判空
队列的删除
队列的尾数据
队列的头数据
队列的销毁
总代码
Queue.h文件
Queue.c文件
什么是队列?
- 队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出 FIFO(First In First Out) 。
- 入队列:进行插入操作的一端称为队尾。
- 出队列:进行删除操作的一端称为队头。
上图理解:

注意:遵循先进先出的原则!这个原则就是区分栈(后进先出)和队列(先进先出)方法!
我们来看看一个队列需要有的最基本要求:详情见--queue - C++ Reference

了解了队列的基本概念,我们来扩展一下!
扩展--循环队列
生活中队列很常用,而在实际的生活中,有时我们会用到循环队列。
循环队列它也有一些应用场景。如:在操作系统中的生产者消费者模型(这个我们后续提到!)
在这种问题中,环形队列可以使用数组实现,也可以使用循环链表实现。
我们图上了解:

空的环形队列:

满的环形队列:

注意:为了能区别Q.front=Q.rear为队满还是队空,我们通常认为Q.rear+1=Q.front为满!
ok!了解了队列的基本,我们来巩固一下:
3.循环队列的存储空间为 Q(1:100) ,初始状态为 front=rear=100 。经过一系列正常的入队与退队操作 后, front=rear=99 ,则循环队列中的元素个数为( )
A .1
B.2
C.99
D.0或者100
4.以下( )不是队列的基本运算?
A.从队尾插入一个新元素
B.从队列中删除第i个元素
C.判断一个队列是否为空
D.读取队头元素的值
5.现有一循环队列,其队头指针为front,队尾指针为rear;循环队列长度为N。其队内有效长度为( )?(假设 队头不存放数据)
A.(rear - front + N) % N + 1
B.(rear - front + N) % N
C.ear - front) % (N + 1)
D.(rear - front + N) % (N - 1)
答案:3.D 4.B 5.B
参考:
3.我们肯定知道元素个数为空时,front=rear,可当front=rear时,也有元素为满的情况!
5.因为是循环队列,单纯尾指针和头指针相减并不能求出总长。
现在我们来实现一下队列(按照一个队列的基本要求)。
当然,队列像栈一样,都可以写成链表和顺序表的底层!这里主要了解链表!
队列的实现
还是老样子:我们创建Queue.h文件声明各种变量和函数,创建Queue.c文件来将函数实现。
思路:
我们在实现一个函数时,要先弄清楚参数。
既然底层是链表,那么就得定义节点!
typedef int QDataType;
//队列节点
typedef struct QueueNode
{struct QueueNode* next;QDataType val;
}QNode;
我们来看看我们的底层逻辑:需要头指针记录头,尾指针记录尾,一个计数变量。
既然需要这几个变量时刻记录,不如我们直接定义一个结构体来管理这些参数。
作用:
这里将参数管理起来可以避免插入和删除函数参数二级指针的使用!(下面会有体现)。
typedef struct Queue
{QNode* phead;QNode* ptail;int size;
}Queue;
ok! 我们来将这些函数一一实现。
初始化
我们得先将记录的参数初始化一下,以便后续参数的更新!
//队列的初始化
void QInit(Queue* p)
{assert(p);p->phead = p->ptail = NULL;p->size = 0;
}
队列的插入
这里谨记:队列是先进先出,栈是后进先出,不要搞混了!
这里由于记录好了尾指针,我们直接在尾后面插入就行!这样看是不是觉得很方便?避免了二级指针的使用。
在插入之前,需要开辟一个节点,然后开始插入!
//队列的插入
void Qpush(Queue* p, QDataType x)
{assert(p);QNode* node = (QNode*)malloc(sizeof(QNode));if (node == NULL){perror("malloc failed!");return;}//初始化节点node->next = NULL;node->val = x;//开始插入if (p->phead == NULL){p->phead = p->ptail = node;}else{p->ptail->next = node;p->ptail = node;}
}
队列的判空
我们只需要在管理的数据变量中判断计数器的值是否为空就行!这也侧面体现了我们用一个结构体管理变量的好处!
//队列的判空
bool QEmpty(Queue* p)
{assert(p);return p->size==0;
}
队列的删除
- 在删除之前,我们要先判断队列是否为空,如果为空的话,不能删除。
- 因为队列是先进先出原则,既然尾部进数据,那么头部出数据。所以我们删除数据要在头部删除!
而在删除时要讨论队列中一个节点还是多个节点问题。本来不讨论我们也能删除数据,那么是为什么要讨论呢?
当队列中只有一个节点时,头指针等于尾指针一起指向这一个节点,当删除时,头指针移向空,然后将这个节点释放掉,但尾指针仍然指向那个节点,当我们访问尾指针指向的那个值时,程序出现错误!
我们上图理解:

于是我们能这样写代码:
//队列的删除
void Qpop(Queue* p)
{assert(p);//删除之前不能为空assert(!QEmpty(p));//讨论队列只有一个节点的情况!if (p->phead->next == NULL){free(p->phead);p->phead = p->ptail = NULL;}else{QNode* next = p->phead->next;free(p->phead);p->phead = next;}p->size--;
}
队列的尾数据
有了前面的基础,我们访问队列尾数据十分简单,但需要注意的是,判断队列是否为空。
//队列的尾数据
QDataType QBack(Queue* p)
{assert(p);assert(!QEmpty(p));return p->ptail->val;
}
队列的头数据
能十分访问尾数据,访问头数据也是如此,但是别忘了要判断队列是否为空。
//队列的头数据
QDataType QFront(Queue* p)
{assert(p);assert(!QEmpty(p));return p->phead->val;
}
队列的销毁
我们动态开辟了内存节点,那么当我们不用了这个队列时,不要忘了销毁它!
//队列的销毁
void QDestroy(Queue* p)
{assert(p);QNode* cur = p->phead;while (cur){QNode* next = cur->next;free(cur);cur = next;}
}
总代码
Queue.h文件
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>typedef int QDataType;
//队列节点
typedef struct QueueNode
{struct QueueNode* next;QDataType val;
}QNode;//队列相关变量
//先进先出
typedef struct Queue
{QNode* phead;QNode* ptail;int size;
}Queue;//队列的初始化
void QInit(Queue* p);
//队列的插入
void Qpush(Queue* p, QDataType x);
//队列的判空
bool QEmpty(Queue* p);
//队列的删除
void Qpop(Queue* p);
//队列的尾数据
QDataType QBack(Queue* p);
//队列的头数据
QDataType QFront(Queue* p);
//队列的销毁
void QDestroy(Queue* p);
Queue.c文件
#include"Queue.h"
//队列的初始化
void QInit(Queue* p)
{assert(p);p->phead = p->ptail = NULL;p->size = 0;
}
//队列的插入
void Qpush(Queue* p, QDataType x)
{assert(p);QNode* node = (QNode*)malloc(sizeof(QNode));if (node == NULL){perror("malloc failed!");return;}//初始化节点node->next = NULL;node->val = x;//开始插入if (p->phead == NULL){p->phead = p->ptail = node;}else{p->ptail->next = node;p->ptail = node;}
}
//队列的判空
bool QEmpty(Queue* p)
{assert(p);return p->phead == NULL;
}
//队列的删除
void Qpop(Queue* p)
{assert(p);//删除之前不能为空assert(!QEmpty(p));//讨论队列只有一个节点的情况!if (p->phead->next == NULL){free(p->phead);p->phead = p->ptail = NULL;}else{QNode* next = p->phead->next;free(p->phead);p->phead = next;}p->size--;
}
//队列的尾数据
QDataType QBack(Queue* p)
{assert(p);assert(!QEmpty(p));return p->ptail->val;
}
//队列的头数据
QDataType QFront(Queue* p)
{assert(p);assert(!QEmpty(p));return p->phead->val;
}
//队列的销毁
void QDestroy(Queue* p)
{assert(p);QNode* cur = p->phead;while (cur){QNode* next = cur->next;free(cur);cur = next;}
}
好了,现在你已经掌握了队列,快去题海感受一下吧!
我们下期见!
相关文章:
【数据结构】详解队列
现在我们来掌握一下队列!如果有对往期知识有不足地方,可翻阅之前文章哦! 个人主页:小八哥向前冲~-CSDN博客 所属专栏:数据结构【c语言版】_小八哥向前冲~的博客-CSDN博客 栈和队列的实现其实都是对你顺序表和链表的检验…...
大模型微调方法汇总
微调方法 Freeze方法P-tuning方法 prefix-tuningPrompt TuningP-tuning v1P-tuning v2Lora方法 重要相关参数LoRA 的优势Qlora方法 相关参数微调经验 模型选择模型大小选择数据处理微调方案英文模型需要做词表扩充吗?如何避免灾难遗忘大模型的幻觉问题微调后的输出…...
探究NVMe SSD HMB应用场景与影响-<续>
如果需要采用HMB功能,需要SSD支持NVME协议且NVMe 1.2及以上版本。NVME协议中对HMB对应有2个关键参数: HMB建议值(HMPRE):设定实际分配给HMB使用的主机内存容量,为设备提供最优性能的内存分配量。 HMB最小值…...
YTU 3166 共享单车 DFS 记忆化搜索
问题 D: 共享单车 题目描述 共享单车走进烟台,小明决定尝试。小明启动共享单车 App,轻松地找到附近的单车。那么问题来了,到最近的那辆单车,小明大约要走多少米呢? 现在简化问题。将地图设定成一个由 100100 米的像…...
RAG应用中的路由模式
依据的用户查询意图在 RAG 应用程序使用“路由控制模式”可以帮助我们创建更强大的 RAG 应用程序。我们通常希望用户能够访问的数据可以来自各种来源,如报告、文档、图片、数据库和第三方系统。 对于基于业务的 RAG 应用程序,我们可能还希望用户能够与其它业务系统进行交互,…...
运维:SSH常用命令简介
SH,全称为Secure Shell,是建立在应用层和传输层基础上的安全协议。SSH 是目前较可靠,专为远程登录会话和其他网络服务提供安全性的协议。利用 SSH 协议可以有效防止远程管理过程中的信息泄露问题。通过 SSH 可以对所有传输的数据进行加密&…...
Springboot+Vue项目-基于Java+MySQL的流浪动物管理系统(附源码+演示视频+LW)
大家好!我是程序猿老A,感谢您阅读本文,欢迎一键三连哦。 💞当前专栏:Java毕业设计 精彩专栏推荐👇🏻👇🏻👇🏻 🎀 Python毕业设计 &…...
力扣刷题:四数相加Ⅱ
题目详情: 解法一:暴力枚举 对于这道题,我们的第一思路就是暴力枚举,我们可以写一个四层的for循环进行暴力匹配,只要相加的结果等于0就进行统计。但是我们会发现,我们的事件复杂度为O(N^4)事件复杂度非常大…...
如果通过Glide 设置图片圆角
要给图片设置一个圆角,通常方法是在ImageView 标签外添加一个CardView 标签,然后设置圆角值,但是今天遇到一个问题就是 RecyclerView Item 中这样操作的话会遇到这样的一个报错: Cannot call this method while RecyclerView is computing a layout or scrolling androidx.rec…...
Chatgpt学习技巧
论文润色指令 论文润色常用指令 通用话术: Below is a paragraph from an academic paper. Polish the writing to meet the academic style, improve the spelling, grammar, clarity, concision and overall readability. When necessary, rewrite the whole se…...
[初学rust] 06_rust 元组
rust 元组 表现形式 和python的元组类似,rust中的元组是一个有序列表,可以包含多种不同类型的数据。 let tup (500, 6.4, a);模式匹配解构元组 和python中的解构一样,rust也支持模式匹配解构元组,但是需要注意的是࿰…...
基于 LlaMA 3 + LangGraph 在windows本地部署大模型 (四)
基于 LlaMA 3 LangGraph 在windows本地部署大模型 (四) 大家继续看 https://lilianweng.github.io/posts/2023-06-23-agent/的文档内容 第三部分:工具使用 工具的使用是人类的一个显着而显着的特征。我们创造、修改和利用外部物体来完成超…...
C++进阶:哈希(1)
目录 1. 简介unordered_set与unordered_map2. 哈希表(散列)2.1 哈希表的引入2.2 闭散列的除留余数法2.2.1 前置知识补充与描述2.2.2 闭散列哈希表实现 2.3 开散列的哈希桶2.3.1 结构描述2.3.2 开散列哈希桶实现2.3.3 哈希桶的迭代器与key值处理仿函数 3.…...
第三节课,功能2:开发后端用户的管理接口-- postman--debug测试
一、如何使用postman 网址: https://www.postman.com/downloads/ 【Postman小白教程】五分钟学会如何使用Postman~_哔哩哔哩_bilibili postman安装使用_bowser agent在postman哪里-CSDN博客 二、下载后 登录,开始测试 2.1 关于postman 报错&#…...
Docker-compsoe部署prysm-beacon-chain + geth服务(geth版本v1.14.0)
1、创建目录结构 ~ # mkdir -p /data/docker-compose/eth ~ # cd /data/docker-compose/eth /data/docker-compose/eth# mkdir beacondata eth ethdata prysm2、编写prysm-beacon-chain Dockerfile和启动脚本文件 /data/docker-compose/eth# vim Dockerfile /data/docker-…...
前端人员如何理解进程和线程
进程和线程的概念: 进程和线程本质都是cpu工作过程的时间片。 进程可以理解为cpu在运行指令即加载保存上下文所要用的时间。也可以理解为一个应用程序运行的实例。 线程是进程中更小的单位,描述一段指令所需要的时间。 进程是资源分配的最小单位…...
Linux下网络命令
目录 需求1-查看本机是否存在22端口解法1解法2解法3 需求2-查看其他主机是否存在22端口解法1解法2解法3 需求3-查看TCP连接解法1/2 需求4-统计80端口tcp连接次数解法 需求5-查看总体网络速度解法 需求6-查看进程流量解法 需求7-dns解法 需求8-traceroute到baidu解法 需求9-查看…...
Php swoole和mqtt
在 PHP 中使用 Swoole 处理 MQTT 订阅消息是一种高效的方式,可以充分利用 Swoole 协程的非阻塞特性和高性能 I/O 处理能力。下面是一个示例代码,演示了如何使用 Swoole 的 MQTT 客户端来订阅消息,并加以详细说明。 1. 安装 Swoole 首先&…...
Spring STOMP-连接到消息代理
STOMP 代理中继维护一个与消息代理的“系统”TCP 连接。这个连接仅用于来自服务器端应用程序的消息,不用于接收消息。您可以为此连接配置STOMP凭据(即STOMP帧的login和passcode头部)。这在XML命名空间和Java配置中都以systemLogin和systemPas…...
Excel中的`MMULT`函数
Excel中的MMULT函数是一个用于执行矩阵乘法运算的函数。矩阵乘法是线性代数中的一个基本运算,它允许我们计算两个矩阵的乘积,得到一个新的矩阵。与普通的标量乘法不同,矩阵乘法涉及到行与列的对应元素相乘然后求和的过程。MMULT函数在进行数据…...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...
Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...
Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习) 一、Aspose.PDF 简介二、说明(⚠️仅供学习与研究使用)三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...
安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...
莫兰迪高级灰总结计划简约商务通用PPT模版
莫兰迪高级灰总结计划简约商务通用PPT模版,莫兰迪调色板清新简约工作汇报PPT模版,莫兰迪时尚风极简设计PPT模版,大学生毕业论文答辩PPT模版,莫兰迪配色总结计划简约商务通用PPT模版,莫兰迪商务汇报PPT模版,…...

