数据结构:队列及其应用
队列(Queue)是一种特殊的线性表,它的主要特点是先进先出(First In First Out,FIFO)。队列只允许在一端(队尾)进行插入操作,而在另一端(队头)进行删除操作。以下是对队列的详细介绍:
一、基本概念
- 队列的定义:队列是一种只允许在表的一端(队尾)进行插入操作,在另一端(队头)进行删除操作的线性表。
- 队头(Front):队列中允许删除的一端,又称为队首。
- 队尾(Rear):队列中允许插入的一端。
- 空队列:不包含任何元素的队列。
二、队列的主要操作
队列的主要操作包括入队(Enqueue)、出队(Dequeue)、查看队头元素(Peek/Front)和判断队列是否为空(IsEmpty)等。
- 入队(Enqueue):在队列的队尾插入一个新元素。
- 出队(Dequeue):从队列的队头删除一个元素,并返回该元素的值。
- 查看队头元素(Peek/Front):返回队列队头元素的值,但不删除该元素。
- 判断队列是否为空(IsEmpty):如果队列中没有任何元素,则返回true;否则返回false。
三、队列的分类(存储结构)
队列根据实现方式的不同,可以分为多种类型,如顺序队列、循环队列、链式队列等。
-
顺序队列:
- 使用数组实现的队列,队头和队尾指针分别指向队列的首尾元素。顺序队列在插入和删除操作时可能会出现“假溢出”现象,即队列未满但因指针限制无法继续插入元素的情况。
初始化:
//initialize
#define MaxSize 50
typedef struct
{int rear,front;//rear指向队尾元素的下一个值,front指向队头元素Elemtype data[MaxSize];
}SqQueue;
-
循环队列:
- 为了解决顺序队列的“假溢出”问题,引入了循环队列。在循环队列中,当队尾指针到达数组末尾时,会自动回到数组的开始位置,形成一个环状结构。循环队列需要牺牲一个存储单元来区分队列空和队列满的状态。
初始:front=rear=0;
队首指针进1:front=(front+1)%MaxSize
队尾指针进1:rear=(rear+1)%MaxSize
队长:(rear-front+Max Size)%MaxSize
队空判断条件:
循环队列为空的判断条件相对简单,即队头指针(front)和队尾指针(rear)相等。这是因为当队列为空时,没有元素被插入,所以队头和队尾都指向数组的起始位置(或某个约定的初始位置)。
队空判断条件:front == rear
队满判断条件:
循环队列为满的判断条件则较为复杂。由于队尾指针在达到数组末尾后会回到数组开头,因此当队尾指针再次指向队头指针时,队列可能已满,也可能为空。为了区分这两种情况,通常采用以下几种方法之一来判断队列是否满:
-
牺牲一个元素空间:
这是最常见的方法。在循环队列中,约定当(rear + 1) % MaxSize == front时,认为队列已满。这里,MaxSize是队列所使用数组的大小,%是取模运算符。这种方法通过牺牲数组中的一个元素空间来区分队列满和队列空的状态。当(rear + 1) % MaxSize == front时,虽然从逻辑上看队尾指针和队头指针相邻,但实际上队列中还有一个空位置没有被使用,因此认为队列已满。队满判断条件(牺牲一个元素空间):
(rear + 1) % MaxSize == front
队空判断条件:front == rear
队长:(rear-front+MaxSize)%MaxSize
-
增设计数器或标志位:(size)
另一种方法是增设一个计数器(记录队列中元素的数量)或标志位(记录队列的当前状态,如是否进行过插入或删除操作)。然而,这种方法需要额外的存储空间,并且增加了操作的复杂性。队空:size=0; 队满:size=maxSize; -
改变front和rear的定义域:
还有一种较为特殊的方法是通过改变front和rear的定义域来区分队列满和队列空的状态。例如,可以约定front的初始值为数组的最大索引加1(或某个大于数组最大索引的值),而rear的初始值为0。这样,当front等于rear时,队列为空;而当rear再次等于front时(在循环过程中),队列满。但这种方法在实际应用中较为少见,因为它改变了front和rear的常规用法。
综上所述,循环队列队空和队满的判断条件主要取决于所采用的具体实现方法。其中,“牺牲一个元素空间”的方法因其简单性和高效性而被广泛采用。
图解:

代码:
//initialize
void InitQueue(SqQueue &Q){Q.front=Q.rear=0;
}
//判断是否为空
bool isEempty(SqQueue Q){if(Q.rear===Q.front)return true;elsereturn false;}
//入队
bool EnQueue(SqQueue &Q,Elemtype x){if ((Q.rear+1)%MaxSize==Q.front)return false; Q.data[Q.rear]=x;Q.rear=(Q.rear+1)%MaxSize;return true;}
//出队
bool DeQueue(SqQueue &Q,Elemtype &x){if(Q.front==Q.rear)return false;x=Q.data[Q.front];Q.front=(Q.front+1)%MaxSize;return true;
}
-
链式队列:
- 使用链表实现的队列,每个节点包含数据域和指向下一个节点的指针。链式队列在插入和删除操作时不需要移动元素,具有较好的灵活性。
代码:
//
typedef struct{Elemtype data;struct LinkNode *next;
}LinkNode;
typedef struct
{LinkNode *rear,*front;
}LinkQueue;//initialize
void InitQueue(LinkQueue &Q){Q.front=Q.rear=(LinkNode*)malloc(sizeof(LinkNode));//建立头结点Q.front->next=NULL;
}bool IsEmpty(LinkQueue Q){if(Q.front==Q.rear)return true;elsereturn false;
}void EnQueue(LinkQueue &Q,ElemType e){LinkNode *s=(LinkNode *)malloc(sizeof(LinkNode));s->data=e;s->next=NULL;Q.rear->next=s;Q.rear=s;
}void DeQueue(LinkQueue &Q,ElemType &e){if(Q.front==Q.rear)return false;LinkNode *s=Q.front->next;e=s->data;Q.front->next=s->next;if(Q.rear==s)//队列中只有一个结点Q.front=Q.rear;//删除后变空free(s);return true;
}
双端队列:
1)能由输入受限的双端队列得到,但不能由输出受限的双端队列得到的是4,1,3,2。
2)能由输出受限的双端队列得到,但不能由输入受限的双端队列得到的是4,2,1,3。
3)既不能由输入受限的双端队列得到,又不能由输出受限的双端队列得到的是4,2,3,1。
四、队列的应用场景
队列在实际应用中有着广泛的应用,如:
- 任务调度:在多任务系统中,可以使用队列来存储待执行的任务,系统按照队列中的顺序依次执行任务。
- 消息传递:在分布式系统中,队列可以用作消息传递的媒介,发送方将消息发送到队列中,接收方从队列中取出消息并进行处理。
- 缓存淘汰:在缓存系统中,可以使用队列的先进先出特性来淘汰最早进入缓存的数据项。
- 并发控制:在多线程或多进程环境中,队列可以用于控制对共享资源的访问顺序,防止数据竞争和死锁等问题。
队列在计算机系统中的应用
队列在计算机系统中的应用非常广泛,以下仅从两个方面来阐述:第一个方面是解决主机与外部设备之间速度不匹配的问题,第二个方面是解决由多用户引起的资源竞争问题。
缓冲区的逻辑结构(2009):
对于第一个方面,仅以主机和打印机之间速度不匹配的问题为例做简要说明。主机输出数据给打印机打印,输出数据的速度比打印数据的速度要快得多,因为速度不匹配,若直接把输出的数据送给打印机打印,则显然是不行的。解决的方法是设置一个打印数据缓冲区,主机把要打印输出的数据依次写入这个缓冲区,写满后就暂停输出,转去做其他的事情。打印机就从缓冲区中按照先进先出的原则依次取出数据并打印,打印完后再向主机发出请求。主机接到请求后再向缓冲区写入打印数据。这样做既保证了打印数据的正确,又使主机提高了效率。由此可见,打印数据缓冲区中所存储的数据就是一个队列。
多队列出队/入队操作的应用(2016):
对于第二个方面, CPU (即中央处理器,它包括运算器和控制器)资源的竞争就是一个典型的例子。在一个带有多终端的计算机系统上,有多个用户需要 CPU 各自运行自己的程序,它们分别通过各自的终端向操作系统提出占用 CPU 的请求。操作系统通常按照每个请求在时间上的先后顺序,把它们排成一个队列,每次把 CPU 分配给队首请求的用户使用。当相应的程序运行结束或用完规定的时间间隔后,令其出队,再把 CPU 分配给新的队首请求的用户使用。这样既能满足每个用户的请求,又使CPU能够正常运行。
五、总结
队列是一种重要的数据结构,它遵循先进先出的原则进行元素的操作。队列的实现方式多样,包括顺序队列、循环队列和链式队列等。队列在实际应用中有着广泛的应用场景,如任务调度、消息传递、缓存淘汰和并发控制等。通过合理使用队列,可以提高系统的性能和稳定性。
相关文章:
数据结构:队列及其应用
队列(Queue)是一种特殊的线性表,它的主要特点是先进先出(First In First Out,FIFO)。队列只允许在一端(队尾)进行插入操作,而在另一端(队头)进行删…...
26个用好AI大模型的提示词技巧
如果你已深入探索过ChatGPT、Microsoft Copilot、风变AI等前沿的生成式AI工具,那么你对“prompt”(提示词)这一核心概念一定有自己的认知。 作为连接你与AI创意源泉的桥梁,“prompt”不仅是触发无限想象的钥匙,更是塑…...
线性表二——栈stack
第一题 #include<bits/stdc.h> using namespace std; stack<char> s; int n; string ced;//如何匹配 出现的右括号转换成同类型的左括号,方便我们直接和栈顶元素 char cheak(char c){if(c)) return (;if(c]) return [;if(c}) return {;return \0;/…...
浏览器发送请求后关闭,服务器的处理过程
之前在开发中,有些后端服务处理非常慢,页面可能会出现504 Gateway time-out的提示,或者服务器还没返回数据,浏览器就关掉了。我们只是看到了浏览器关掉,但是服务器和客户端的状态都是什么样的呢? 问题 在…...
tee命令:轻松同步输出到屏幕与文件
一、命令简介 tee 命令在 Linux 和 Unix 系统中用于读取标准输入的数据,并将其同时输出到标准输出和文件中。简单来说,tee 命令可以用来分割数据流,使其既能够被输出到屏幕,也能够被写入到文件中。 二、命令参数…...
【经验技巧】如何做好S参数的仿测一致性
根据个人经验,想要做好电路板S参数的仿测一致性,如下的相关信息必须被认真对待: 1. PCB叠构(Stack up),仿真模型需要保证设计参数与板厂供应商的生产参数完全一样,这些参数包括: 叠层结构数据;介电常数;损耗因子;蚀刻因子;表面粗糙度。 2. 仿真中,需要保证信号测试…...
js逆向——webpack实战案例(一)
今日受害者网站:https://www.iciba.com/translate?typetext 首先通过跟栈的方法找到加密位置 我们跟进u函数,发现是通过webpack加载的 向上寻找u的加载位置,然后打上断点,刷新网页,让程序断在加载函数的位置 u r.n…...
Spring Boot 进阶-Spring Boot的全局异常处理机制详解
我们知道在软件运行的过程中,总会出现各种各样的问题,各种各样的异常,而程序员的主要任务之一就是解决在程序运行过程中出现的这些异常。在很多程序员开发的代码中我们会看到在关键的地方为了保证程序能够有一个正常的反馈,大量地使用了try catch finally语句。 大量的try …...
滚雪球学MySQL[7.1讲]:安全管理
全文目录: 前言7. 安全管理7.1 用户与权限管理7.1.1 创建和管理用户7.1.2 权限分配与管理7.1.3 最小权限原则 7.2 安全策略配置7.2.1 使用加密连接7.2.2 强密码策略7.2.3 定期审计和日志管理 7.3 SQL注入防范7.3.1 使用预处理语句7.3.2 输入验证与清理7.3.3 最小化数…...
反射及其应用---->2
目录 1.使用类对象 1.1创建对象 1.2使用对象属性 1.3使用方法 2.反射操作数组 3.反射获得泛型 4.类加载器 4.1双亲委派机制 4.2自定义加载器 1.使用类对象 通过反射使用类对象,主要体现3个部分 创建对象,调用方法,调用属性ÿ…...
[Python学习日记-32] Python 中的函数的返回值与作用域
[Python学习日记-32] Python 中的函数的返回值与作用域 简介 返回值 作用域 简介 在函数的介绍中我们提到了函数的返回值,当时只是做了简单的介绍,下面我们将会进行详细的介绍和演示,同时也会讲一下 Python 中的作用域,作用域分…...
儿童发光耳勺值得买吗?儿童发光耳勺最建议买的五个牌子!
儿童耳部清洁需谨慎,发光耳勺能在光线不足时提供照明,便于看清耳道。但不同产品质量参差不齐,选择时需综合考虑安全性、实用性等因素,为孩子的耳部健康做出正确选择! 这里给大家总结了全新的儿童发光耳勺的避雷指南&am…...
TIPS 二进制程序暴露符号给动态链接库使用
背景 在支持插件/扩展的C/C系统中,通常会支持在程序运行时加载动态链接库。这时二进制程序会提供一些函数/接口让动态链接库调用,但是这些函数在二进制程序中又不会使用,导致在编译时编译器直接把这些符号删除了,加载链接库就会由…...
【分布式微服务云原生】8分钟掌握微服务通信的艺术:Dubbo与OpenFeign全面解析
摘要: 在构建微服务架构时,服务间的通信机制是核心要素之一。Dubbo和OpenFeign是两个非常流行的服务调用框架,它们各有千秋,适用于不同的场景。本文将深入探讨Dubbo和OpenFeign的主要特点、使用场景以及它们之间的差异,…...
sicp每日一题[2.33]
Exercise 2.33 Fill in the missing expressions to complete the following definitions of some basic list-manipulation operations as accumulations: ; p 表示一个函数,sequence 表示一个列表 ; 这个函数将对列表中每一个元素进行 p 操作 (define (map p sequ…...
【Mybatis】常见面试题汇总 共56题
文章目录 1. 介绍下MyBatis?2. MyBatis 框架的应用场景?3. MyBatis 有哪些优点?4. MyBatis 有哪些缺点?5. MyBatis 用到了哪些设计模式?6. MyBatis常用注解有哪些?7. MyBatis 有哪些核心组件?8. MyBatis编程步骤是什么样的?9. MyBatis 和…...
每天一道面试题(17):服务网格学习笔记
什么是服务网格? 服务网格(Service Mesh)是处理微服务间通信的一种基础设施层。它主要用于解耦服务间的通信与业务逻辑,使开发者可以专注于业务实现。服务网格在微服务架构的演进中扮演了重要角色,特别是在解决服务间…...
【nrm】npm 注册表管理器
nrm是什么 nrm(NPM Registry Manager)是一个用于管理 Node.js 包管理器(如 npm 和 Yarn)的注册表工具。它可以帮助用户快速切换不同的 npm 源,以便于提高包安装的速度和效率,特别是在中国大陆地区…...
解压短视频素材资源网站推荐
如果你正在寻找解压短视频素材,那么这篇文章正是为你而写!以下是一些热门的网站,帮助你轻松找到所需的素材,快来看看吧! 蛙学网 蛙学网是国内领先的视频素材网站,提供丰富的解压视频素材。无论是放松心情的…...
Qemu开发ARM篇-6、emmc/SD卡AB分区镜像制作并通过uboot进行挂载启动
文章目录 1、AB分区镜像制作2、uboot修改3、镜像启动 在上一篇 Qemu开发ARM篇-5、buildroot制作根文件系统并挂载启动中,我们通过buildroot制作了根文件系统,并通过 SD卡的形式将其挂载到设备并成功进行了启动,但上一章中,我们的…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...
QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...
【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
HarmonyOS运动开发:如何用mpchart绘制运动配速图表
##鸿蒙核心技术##运动开发##Sensor Service Kit(传感器服务)# 前言 在运动类应用中,运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据,如配速、距离、卡路里消耗等,用户可以更清晰…...
JVM虚拟机:内存结构、垃圾回收、性能优化
1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...
动态 Web 开发技术入门篇
一、HTTP 协议核心 1.1 HTTP 基础 协议全称 :HyperText Transfer Protocol(超文本传输协议) 默认端口 :HTTP 使用 80 端口,HTTPS 使用 443 端口。 请求方法 : GET :用于获取资源,…...
