数据结构:队列及其应用
队列(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卡的形式将其挂载到设备并成功进行了启动,但上一章中,我们的…...

IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...

3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...

2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...
Bean 作用域有哪些?如何答出技术深度?
导语: Spring 面试绕不开 Bean 的作用域问题,这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开,结合典型面试题及实战场景,帮你厘清重点,打破模板式回答,…...

破解路内监管盲区:免布线低位视频桩重塑停车管理新标准
城市路内停车管理常因行道树遮挡、高位设备盲区等问题,导致车牌识别率低、逃费率高,传统模式在复杂路段束手无策。免布线低位视频桩凭借超低视角部署与智能算法,正成为破局关键。该设备安装于车位侧方0.5-0.7米高度,直接规避树枝遮…...

macOS 终端智能代理检测
🧠 终端智能代理检测:自动判断是否需要设置代理访问 GitHub 在开发中,使用 GitHub 是非常常见的需求。但有时候我们会发现某些命令失败、插件无法更新,例如: fatal: unable to access https://github.com/ohmyzsh/oh…...