【数据结构】队列的实现与优化指南

一、前言

队列是一种重要的数据结构,它按照“先入先出”(FIFO)的原则管理数据。本文将介绍队列的概念、应用场景,以及如何使用数组实现普通队列和环形队列。


二、内容

2.1 概述

(1)什么是队列?

队列(Queue)是一种常见的数据结构,它是一个线性数据结构,按照先入先出(FIFO,First-In-First-Out)的原则来管理数据。

注意,先入先出的原则就意味着最早进入队列的元素将最先被取出,而最后进入队列的元素将最后被取出,类似于排队等候服务的行为。

队列可以使用数组或链表来实现,具体实现方式因应用需求而异。

队列支持两种主要的操作,即入队(Enqueue)和出队(Dequeue)。

  • 入队:将元素添加到队列的尾部。
  • 出队:从队列的头部取出元素并删除它。

(2)应用场景

队列的应用场景有很多,比如:

  1. 任务调度:操作系统使用队列来管理待执行的任务或进程,确保按照进入队列的顺序分配处理时间。
  2. 数据缓冲:队列用于数据传输和处理中,特别是在异步通信或生产者-消费者模式中,可以缓冲待处理的数据。
  3. 广度优先搜索:在图论和搜索算法中,队列用于实现广度优先搜索,以逐层遍历图结构。
  4. 打印任务队列:打印机队列用于管理待打印的文档,确保按照顺序打印。
  5. 网页请求队列:Web服务器可以使用队列来处理收到的请求,以便有序响应客户端请求。
  6. 排队系统:在银行、餐馆、医院等场所,队列被用来管理等待服务的客户,确保服务按照先来先服务的原则。
  7. ......

队列在计算机科学和实际应用中非常有用,因为它们提供了一种有效的方法来管理和调度数据或任务,以确保按照特定的顺序进行处理。


2.2 数组模拟队列

下面,我们用数组来模拟一个简单的队列数据结构。

(1)队列类定义

首先给出类的定义:

class ArrayQueue {private int maxSize;private int front;private int rear;private int[] data;ArrayQueue(int queueMaxSize) {maxSize = queueMaxSize;    // 队列的最大容量data = new int[maxSize];    // 存放队列的数据front = -1;    // 指向队列头的前一个位置rear = -1;     // 直接指向队列尾部}// ... 方法定义
}

在这里,ArrayQueue 是一个队列类,使用数组作为内部数据存储。它包括最大容量(maxSize)、队列头(front)、队列尾(rear)和一个整数数组(data)来存放队列的数据。

构造函数 ArrayQueue 接受一个整数参数 queueMaxSize,表示队列的最大容量。初始化时,队列的头(front)和尾都(rear)被置为-1,表示队列为空。

需要注意这里的定义,在这里,front 变量指的是指向队列首元素的前一个位置,而 rear 变量则指向队列的尾部元素,即最后一个元素。

因此,初始队列的结构图如下:

image-20231016142126890.png

(2)isEmpty

public boolean isEmpty() {return rear == front;
}

isEmpty() 方法用于检查队列是否为空。如果队列头和队列尾相等,表示队列中没有数据,返回 true;否则返回 false

(3)isFull

public boolean isFull() {return rear == maxSize - 1;
}

isFull() 方法用于检查队列是否已满。如果队列尾等于最大容量减1,表示队列已满,返回 true;否则返回 false

(4)enQueue

// 入队操作,添加数据到队尾
public void enQueue(int num) {if(isFull()) {System.out.println("队列已满,无法入队");return;}rear++;data[rear] = num;
}

enQueue 方法用于将数据添加到队列的尾部。首先,它会检查队列是否已满,如果是,将输出一条错误消息并不执行入队操作。如果队列未满,将 rear 后移,然后将数据存入队列尾部。

再次强调一下,这里的 rear 变量用于指向队列的最后一个数据,即队列的尾部。

image-20231016142544266.png

(5)deQueue

// 出队操作,取出队头数据
public int deQueue() {if(isEmpty()) {throw new RuntimeException("队列为空,无法出队"); }front++;return data[front];
}

deQueue 方法用于取出队列头部的数据。首先,它会检查队列是否为空,如果是,将抛出一个运行时异常。如果队列不为空,将 front 后移,然后返回队头的数据。

再次强调一下,这里的 front 变量指向的是队列头数据的前一个位置。

image-20231016142948770.png

(6)headQueue

// 查看队头数据(注意不是取出数据)
public int headQueue() {if(isEmpty()) {throw new RuntimeException("队列为空,没有数据");}return data[front+1];
}

headQueue 方法用于获取队列头部的数据,但不会将其出队。它会检查队列是否为空,如果是,将抛出一个运行时异常。如果队列不为空,将返回队头的数据。

(7)showQueue

// 打印队列
public void showQueue() {if(isEmpty()) {System.out.println("队列为空,没有数据");return;}// 简单的遍历队列for(int i = 0; i < data.length; i++) {System.out.printf("data[%d] = %d\n", i, data[i]);}
}

showQueue 方法用于简单地打印队列的所有元素。如果队列为空,将输出一条消息表示队列为空。否则,它会简单地遍历队列,打印每个数据元素的索引和值。


2.3 数组模拟环形队列

(1)存在的问题

我们再来思考一个问题,虽然上述的队列类实现了一个简单的队列数据结构,但仍然存在弊端。那就是数组使用一次后不能复用

什么意思?

具体的,我们可以发现,每当队列入队一个数据,rear 变量就会往后移一位。每当有元素出队,front 变量也会往后移一位。但是!一旦 rear 变量到达队列的尾部,如果队列头部仍有空余的空间,就像这样:

image.png

那么此时根据 isFull() 方法的判断下,该队列是满的。因此无法再入队。

因此我们说,对于之前的队列简单实现来说,一旦队列中的数据元素被取出,对应的数组位置就不能再次使用。数据从头部添加,从尾部取出。一旦数组被填满,我们无法再添加新的数据,即使队列的前面已经有一些位置被释放出来。这就会导致内存资源浪费

为了解决这个问题,我们考虑使用环形队列来优化。

什么是环形队列

事实上,环形队列是一种更高效的队列实现方式,它允许队列在达到最大容量后继续添加元素,以覆盖掉队列头部已经被取出的数据,实现数据的循环复用。

我们通过取模运算 % 来实现环形队列。

(2)思路分析

当我们考虑了队列内部数据存储资源的复用后,我们就需要对 front 和 rear 变量的含义进行一个的调整(当然不调整也行,看个人习惯)。

具体如下:

  • front 变量:
    • 表示指向队列的第一个元素,即首元素。
    • data[front] 是队列的第一个元素。
    • front的初始值为 0。
  • rear 变量:
    • 表示指向队列最后一个元素的下一个位置
    • 这是为了表示队列中哪些位置是可用的,以便继续添加新的元素。
    • rear 的初始值同样为 0。

当我们这样约定好了后,就可以开始着手编写代码,得到一个环形队列。

此时判断队列已满或空时,逻辑需要略微调整。

判断环形队列空时,条件为:(rear == front)。因为当 rear 指针等于 front 指针时,表示队列没有有效的元素,即队列为空。

判断环形队列满时,条件为:(rear + 1) % maxSize == front

这该怎么理解?

事实上,在含义调整后,环形队列中的 rear 变量指向的位置实际上就是预留给下次入队的数据存放的位置

当有一个新的数据入队时,rear 指向的位置就可以存储本次入队的数据的值,然后,rear 就会加一并取余 maxSize ,用于寻找下一个可以存储入队数据的位置。

因此,当(rear + 1) % maxSize 的值刚好等于 front,那么证明该环形队列已经满了,没有地方可以存储下一次入队的值。

举一个例子,假设 maxSize 为 3,初始时 front 和 rear 都是0:

  • 队列为空:front = 0rear = 0
  • 插入一个元素:front = 0rear = 1
  • 插入第二个元素:front = 0rear = 2
  • 插入第三个元素:front = 0rear = 0(此时队列满,因为 (rear + 1) % maxSize 等于 front
  • 取出第一个元素:front = 1rear = 0(此时队列有效元素个数为 2,因为 (0+3-1) % 3 == 2

示意图如下:

image-20231016153249708.png

(3)优化后的队列类

优化后的代码实现如下:

class CircleArrayQueue {private int maxSize;private int front;    // 初始值为 0,指向队头数据,即首元素private int rear;     // 初始值为 0,指向队尾数据的下一个位置private int[] data;ArrayQueue(int queueMaxSize) {maxSize = queueMaxSize;	data = new int[maxSize];}// 判断队列是否为空public boolean isEmpty() {return rear == front;}// 判断队列是否满public boolean isFull() {return (rear + 1) % maxSize == front;}// 入队:添加数据到队尾public void enQueue(int num) {if(isFull()) {System.out.println("队列已满,无法入队");return;}data[rear] = num;rear = (rear + 1) % maxSize;}// 出队,取出队头数据public int deQueue() {if(isEmpty()) {throw new RuntimeException("队列为空,无法出队"); }int value = data[front];front = (front + 1) % maxSize;return value;}// 显示队列的头数据(不是取出数据)public int headQueue() {if(isEmpty()) {throw new RuntimeException("队列为空,没有数据");}return data[front];}// 返回环形队列当前的元素个数public int size() {return (rear + maxSize - front) % maxSize;}// 打印队列public void showQueue() {if(isEmpty()) {System.out.println("队列为空,没有数据");return;}// 遍历思路,从 data[front] 遍历到 data[front + size]for(int i = front; i < front + size(); i++) {System.out.printf("data[%d] = %d\n", i%maxSize, data[i%maxSize]);}}
}

三、总结

本文详细介绍了队列数据结构的概念和应用,包括普通队列和环形队列的实现。队列是一种有序的数据结构,它在计算机科学中被广泛应用,用于管理数据和任务的顺序执行。普通队列使用数组实现,但存在内存资源浪费的问题。为了解决这个问题,我们引入了环形队列的概念,它允许队列数据的循环复用,更加高效地利用内存。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《软件方法》2023版第1章(10)应用UML的建模工作流-大图

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 1.4 应用UML的建模工作流 1.4.1 概念 我用类图表示建模工作流相关概念如图1-16。 图1-16 建模工作流相关概念 图1-16左侧灰色部分定义了“游戏规则”&#xff0c;右侧则是在“游戏规…

30W网络对讲广播一体音柱

SV-7042T 30W网络对讲广播一体音柱 一、描述 SV-7042T是深圳锐科达电子有限公司的一款壁挂式网络有源音柱&#xff0c;具有10/100M以太网接口&#xff0c;可将网络音源通过自带的功放和喇叭输出播放&#xff0c;其采用防水设计&#xff0c;功率可以从20W到40W。SV-7042T作为网…

pycharm操作git

pycharm操作git 之前用命令做的所有操作&#xff0c;使用pychrm点点就可以完成 克隆代码 上方工具栏Git ⇢ \dashrightarrow ⇢ Clone ⇢ \dashrightarrow ⇢ 填写地址&#xff08;http、ssh&#xff09; 提交到暂存区&#xff0c;提交到版本库&#xff0c;推送到远程 直接…

淘宝拍立淘接口,按图搜索商品接口,图片识别接口,图片上传搜索接口,图片搜索API接口,以图搜货接口

淘宝拍立淘图片搜索接口可以通过上传或输入图片链接的方式&#xff0c;调用淘宝的图片搜索引擎&#xff0c;返回与该图片相关的所有淘宝商品。 使用该接口需要先申请淘宝开放平台的App Key和App Secret&#xff0c;获取相应的API访问权限。在调用接口时&#xff0c;需要传入商…

ShareMouse for Mac(多台电脑鼠标键盘共享软件)

ShareMouse mac版是一款Mac平台上可以在多台电脑间共享鼠标的工具软件&#xff0c;sharemousefor Mac支持 Windows 与 Mac&#xff0c;并可以在不同电脑间共享剪贴板。只需要移动鼠标指针的到想控制的显示器那里去、鼠标光标就会神奇地“跨越”到邻近的电脑屏幕上。每个计算机都…

敏朗公益 · 童心共融:福州市实验幼儿园携手敏朗共同举办活动!

2023年3月31日&#xff0c;福州市敏朗公益服务中心联合福州市实验幼儿园开展“童年童趣童心共融”主题融合活动&#xff0c;让星儿体验幼儿园生活&#xff0c;与普龄儿童一同分享快乐的童年。 本场活动是由福州市鼓楼区民政局、鼓楼区残疾人联合会指导&#xff0c;在第16届世界…

淘宝店铺所有商品数据接口及店铺商品数据分析

获取淘宝店铺所有商品数据的接口是淘宝开放平台提供的接口&#xff0c;通过该接口可以获取店铺所有商品数据。 通过淘宝开放平台接口获取店铺所有商品数据的方法如下&#xff1a; 在开放平台注册成为开发者并创建一个应用&#xff0c;获取到所需的 App Key 和 App Secret 等信…

可视化工具Datart踩(避)坑指南(6)——避免多人同时编辑

作为目前国内开源版本最好用的可视化工具&#xff0c;Datart无疑是低成本高效率可供二开的可视化神兵利器。当然&#xff0c;免费的必然要付出一些踩坑的代价。本篇我们来讲一讲可视化工具Datart踩&#xff08;避&#xff09;坑指南&#xff08;6&#xff09;之避免多人同时编辑…

PAM从入门到精通(九)

接前一篇文章&#xff1a;PAM从入门到精通&#xff08;八&#xff09; 本文参考&#xff1a; 《The Linux-PAM Application Developers Guide》 先再来重温一下PAM系统架构&#xff1a; 更加形象的形式&#xff1a; 五、主要函数详解 7. pam_authenticate 概述&#xff1a; …

即刻报名,企业服务与新经济论坛亮点提前揭秘!

峰会官网已上线&#xff0c;最新议程请关注&#xff1a;doris-summit.org.cn 即刻报名 Doris Summit 是 Apache Doris 社区一年一度的技术盛会&#xff0c;由飞轮科技联合 Apache Doris 社区的众多开发者、企业用户和合作伙伴共同发起&#xff0c;专注于传播推广开源 OLAP 与实…

【算法 | 位运算No.1】leetcode268. 丢失的数字

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【Leetcode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…

JDBC 和数据库连接池

文章目录 1. JDBC概述1.1 基本介绍1.2 模拟JDBC1.3 JDBC 带来的好处1.4 JDBC API 2. JDBC 快速入门2.1 JDBC 程序编写步骤2.2 JDBC 第一个程序 3. 获取数据库连接 5 种方式3.1 方式 13.2 方式 23.3 方式 33.4 方式 43.5 方式 53.6 课堂练习 4. ResultSet [ 结果集]5. Statement…

软考(高级)是否需要报班,大家有什么建议?

对于报考高级专业领域还不确定。根据我的个人经验&#xff0c;我强烈建议不要犹豫&#xff0c;直接报班。时间非常紧张&#xff0c;务必抓紧学习重点&#xff0c;不要漫无目的地自学。免费的学习方式往往会付出更多的时间成本。请考虑自身经济情况。 尽管自学考试自由度高&…

视频下载小助手儿开通了视频号下载功能

不少人对视频号都有视频下载的需要&#xff0c;但由于平台并不提供该功能&#xff0c;我们视频下载小助手儿&#xff0c;就提供了视频号的视频下载功能。 为什么起名叫下载小助手儿呢&#xff1f; 下载小助手儿更直观让用户了解到他可以下载视频号的视频&#xff0c;但不局限与…

IStoreOS结合内网穿透软件Cpolar实现公网远程访问

文章目录 前言1. ssh局域网登陆iStoreOS系统2. 安装Cpolar内 网穿透软件3. 测试公网远程链接4. 公网使用固定http地址远程访问iStoreOS webui界面 前言 iStoreOS系统是基于OpenWrt定制的软路由系统&#xff0c;提供了如轻nas&#xff0c;云盘&#xff0c;文件共享等众多网络服务…

相似性搜索:第 7 部分--LSH 组合物

Vyacheslav Efimov – Medium S相似性搜索是一个问题&#xff0c;给定一个查询&#xff0c;目标是在所有数据库文档中找到与其最相似的文档。 一、说明 在数据科学中&#xff0c;相似性搜索经常出现在 NLP 领域、搜索引擎或推荐系统中&#xff0c;其中需要检索最相关的文档或项…

【Java系列】Java 简介

目录 Java 简介主要特性发展历史Java 开发工具系列文章版本记录 Java 简介 Java 是由 Sun Microsystems 公司于 1995 年 5 月推出的 Java 面向对象程序设计语言和 Java 平台的总称。由 James Gosling和同事们共同研发&#xff0c;并在 1995 年正式推出。 后来 Sun 公司被 Ora…

黑豹程序员-架构师学习路线图-百科:MySQL

文章目录 1、什么是MySQL2、MySQL受喜爱程度经典四人组&#xff1a; 3、发展历史4、MariaDB 1、什么是MySQL MySQL是一个关系型数据库管理系统&#xff0c;由瑞典MySQL AB 公司开发&#xff0c;属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一&#xff0c;在 …

canvas绘制扫描图

先定义一个canvas <div class"canFa"><canvas width"380" id"can3"></canvas></div>主要绘制函数 var chosHeight document.getElementsByClassName("canFa")[0].children[0].clientHeight;var chosWidth …

Anthropic全球上线AI语言模型Claude 2;多模态系统:融合文本和图像的新前沿

&#x1f989; AI新闻 &#x1f680; Anthropic全球上线AI语言模型Claude 2&#xff0c;编程、数学、推理能力大幅提升 摘要&#xff1a;Anthropic在全球正式上线了AI语言模型Claude 2。相比前代版本&#xff0c;Claude 2在编程、数学、推理等方面都有大幅提升&#xff0c;支…