Java 数据结构篇-用链表、数组实现队列(数组实现:循环队列)

🔥博客主页: 【小扳_-CSDN博客】
❤感谢大家点赞👍收藏⭐评论✍
 

文章目录

        1.0 队列的说明

        1.1 队列的几种常用操作

        2.0 使用链表实现队列说明

        2.1 链表实现队列

        2.2 链表实现队列 - 入栈操作

        2.3 链表实现队列 - 出栈操作

        2.4 链表实现队列 - 获取队头元素操作(不删除)

        2.5 链表实现队列 - 获取队列有效元素个数操作

        2.6 链表实现队列 - 判空处理操作

        2.7 用链表实现队列的完整代码

        3.0 使用数组实现循环队列说明

        3.1 数组实现循环队列的操作

        3.2 数组实现循环队列 - 入队列操作

        3.3 数组实现循环队列 - 出队列操作

        3.4 数组实现队列 - 得到队头元素操作(不删除)

        3.5 数组实现队列 - 得到队尾元素操作(不删除)

        3.6 数组实现队列 - 判空队列操作

        3.7 数组实现队列 - 判满队列操作

        3.8 用数组实现队列完整代码


        1.0 队列的说明

        队列是一种线性数据结构,具有先进先出First In First Out,FIFO)的特性。它类似于排队的概念,新元素被添加到队列的尾部而从队列中移除元素时则从队列的头部开始。队列通常用于需要按照特定顺序处理元素的场景,比如任务调度、消息传递等。

        1.1 队列的几种常用操作

                - 队首元素(front):队列的头部元素。

                - 队尾元素(rear):队列的尾部元素。

                - 入队(offer):将新元素添加到队列的尾部。

                - 出队(poll):从队列的头部移除元素。

                - 获取队头元素(peek):从队列的头部获取元素,不移除。

                - 判空(isEmpty):判断队列是否为空。

                - 判满(isFull):判断队列是否已满(对于有限大小的队列)。

                - 元素个数(size):获取队列有效的元素个数。

接口代码如下:

public interface QueueInterface{/*** 入列*/boolean offer(int e);/*** 出列*/int poll();/*** 获取队列头元素*/int peek();/*** 获取队列中有效元素个数*/int size();/*** 检验队列是否为空*/boolean isEmpty();
}

        2.0 使用链表实现队列说明

        使用链表实现队列,无疑就是用链表的数据结构的方式来实现队列的操作(实现队列的接口)。跟栈不同的是:栈只能对一端进行操作,而队列是对头尾进行操作。一般对于单链表来说,头节点当作队列中的队头(front)尾节点当作队列中的队尾(rear)。而入队列相当于尾插,在链表尾部插入节点,出队列相当于头删,在链表头部删除头节点。对于双向链表来说,就比较自由了,头节点既可以作为队头,也可以作为队尾。尾节点既可以作为队头,也可以作为队尾。

        2.1 链表实现队列

        用双向链表来实现队列,既然头尾都可以作为队列,选其中一种即可,对于队尾来说也是如此。这里就用头节点作为队列中的队头,而尾节点作为队列中的队尾。

简单分析:

        - 实现入栈操作:在链表尾部插入节点即可。

        - 实现出栈操作:在链表头部删除节点即可。

        - 实现获取队列头部元素:获取链表头部节点的元素即可。

        - 实现总计有效元素个数:需要定义一个成员变量 size ,入栈时进行 size++ ,出栈时  size--

        - 实现判空处理:当 size == 0 ,则为空队列。

        - 实现判断满队列:当 size >= 创建队列时默认大小,则为满队列。

        2.2 链表实现队列 - 入栈操作

                实现入栈操作:在链表尾部插入节点即可。分为两种情况:当队列为空时,则入栈的节点即是队头也是队尾当队列不为空时,则入栈的节点一般来说就是新的队尾。每一次入栈完成后,都需要进行 size++

代码如下:

    //入列@Overridepublic boolean offer(int e) {if (isEmpty()) {front = rear = new Node(null,e,null);size++;return true;}Node node = new Node(rear,e,null);rear.next = node;rear = node;size++;return true;}

        2.3 链表实现队列 - 出栈操作

                实现出栈操作:在链表头部删除节点即可。出栈一般分为三种情况:

        第一种情况,当队列为空时,不应该出栈了,直接返回 -1 或者抛异常。

        第二种情况,当只有一个节点时,出栈之后,就不会再有元素了,所以 frontrear 需要置为空。返回出栈节点的值即可。

        第三种情况,除了第一、二种情况之后,第三种情况就可以正常的进行头删节点操作处理了。需要注意的是,出栈完成后,进行 size-- 。最后,返回出栈节点的数值即可。

代码如下:

 

    //出列@Overridepublic int poll() {if (isEmpty()){return -1;}//注意特例:只有一个节点的情况if (front.next == null) {int temp = front.val;front = null;rear = null;return temp;}Node temp = front;front = front.next;front.prev = null;size--;return temp.val;}

        2.4 链表实现队列 - 获取队头元素操作(不删除)

                获取链表头部节点的元素即可。一般分为两种情况:当队列为空时,可以返回 -1 或者抛异常处理当队列不为空时,直接返回头部节点的值即可

代码如下:

    @Overridepublic int peek() {if (isEmpty()) {return -1;}return front.val;}

        2.5 链表实现队列 - 获取队列有效元素个数操作

                直接返回 size 即可。

    @Overridepublic int size() {return size;}

        2.6 链表实现队列 - 判空处理操作

                size == 0 时,返回 true 。否则返回 false 。也可以用 front == null 来判断是否为空队列。

代码如下:

    @Overridepublic boolean isEmpty() {return front == null;}

 

        2.7 用链表实现队列的完整代码

public class MyLinkedQueue implements QueueInterface {static class Node {public Node prev;public int  val;public Node next;public Node(Node prev, int val, Node next) {this.prev = prev;this.val = val;this.next = next;}}private Node front;private Node rear;private int size;//入列@Overridepublic boolean offer(int e) {if (isEmpty()) {front = rear = new Node(null,e,null);size++;return true;}Node node = new Node(rear,e,null);node.prev = rear;rear.next = node;rear = node;size++;return true;}//出列@Overridepublic int poll() {if (isEmpty()){return -1;}//注意特例:只有一个节点的情况if (front.next == null) {int temp = front.val;front = null;rear = null;return temp;}Node temp = front;front = front.next;front.prev = null;size--;return temp.val;}@Overridepublic int peek() {if (isEmpty()) {return -1;}return front.val;}@Overridepublic int size() {return size;}@Overridepublic boolean isEmpty() {return front == null;}}

 

        3.0 使用数组实现循环队列说明

        用数组实现队列,一般来说是循环队列,循环队列可以解决普通队列在出队操作后产生的空间浪费问题,同时可以利用数组的固定大小来实现队列的循环利用。

循环队列的接口代码如下:

public interface QueueInterface{/*** 入列*/boolean offer(int e);/*** 出列*/int poll();/*** 获取队列头元素,不删除*/int peek();/*** 检验队列是否为空*/boolean isEmpty();/*** 判断是否为满队列*/boolean isFull();/*** 得到队尾元素,不删除*/int Rear();
}

        使用数组实现队列,无疑就是用数组的数据结构的方式来实现队列的操作(实现队列的接口)。循环队列的关键是使用两个指针来标记队列的头部和尾部,分别称为 front rear 当入队时,rear 指针向后移动当出队时,front 指针向后移动。当 rear 指针到达数组的末尾时,可以通过取模运算将 rear 指针置为 0 ,实现循环的效果。

        3.1 数组实现循环队列的操作

                - 入队操作:将元素添加到 rear 指针所指向的位置,并更新 rear 指针。

                - 出队操作:front 指针所指向的位置移除元素,并更新 front 指针。

                - 判空操作:front 指针等于 rear 指针时,队列为空。

                - 判满操作: (rear+1) % 数组长度等于 front 指针时,队列为满。

        3.2 数组实现循环队列 - 入队列操作

                将元素添加到 rear 指针所指向的位置,并更新 rear 指针。更新 rear 就是往后走一步,但是为了实现循环,可不能简单的进行 +1 处理,需要 rear = (rear + 1) % arr.length,这样就可以数组中循环走了。在入队前,需要先判断是否为满队列了。

代码如下:

    // 入队列@Overridepublic boolean offer(int e) {if (isFull()) {return false;}arr[rear] = e;rear = (rear+1) % arr.length;return true;}

         3.3 数组实现循环队列 - 出队列操作

                front 指针所指向的位置移除元素,并更新 front 指针。同样的,更新可不能简单的 +1 处理,需要将 front = (front + 1) % arr.length ,每次出栈前需要记录一下出栈的元素,接着才往后走,最后返回记录的元素即可。出栈前,需要判断是否为空队列,如果为空队列,就需要抛异常或者返回 -1 处理。

代码如下:

    //出队列@Overridepublic int poll() {if (isEmpty()) {return -1;}int temp = arr[front];front = (front + 1) % arr.length;return temp;}

        3.4 数组实现队列 - 得到队头元素操作(不删除)

                先判断是否为空队列,若不是,则返回队头元素即可。

代码如下:

    //得到队头元素,不删除@Overridepublic int peek() {if (isEmpty()) {return -1;}return arr[front];}

         3.5 数组实现队列 - 得到队尾元素操作(不删除)

                先判断队列是否为空,如果为空队列,则返回 -1 或者抛异常。如果不为空,则需要返回 arr[rear - 1],但是需要注意的是:有一种情况需要额外考虑进去,当 rear == 0 时,那么 rear - 1 == -1 所以不合理,数组中的索引不存在 -1 。因此这个情况要分开讨论,当 rear == 0 时,那么需要返回的值为 arr[arr.length - 1]当 rear != 0 时,那么返回的值为 arr[rear - 1]

代码如下:

    //得到队尾元素,不删除@Overridepublic int Rear() {if (isEmpty()) {return -1;}int temp = (rear == 0) ? arr.length - 1 : rear - 1;return arr[temp];}

        3.6 数组实现队列 - 判空队列操作

                当且仅当 rear == front 时,则队列为空

代码如下:

    @Overridepublic boolean isEmpty() {return front == rear;}

        3.7 数组实现队列 - 判满队列操作

                有很多种方式可以来判断队列是否满,比如,定义 size 变量来总计元素个数,然后跟 arr.lengrh 进行对比,相等即满队列了,不相等即为还没有满队列使用标记也可以实现判断是否为满队列。

        这里介绍牺牲空间来判断满队列,即当且仅当 (rear + 1) % arr.lengrh == front 时,该队列满了。由于这里牺牲了一个空间,所以需要在自定义初始化数组大小的时候额外 +1

代码如下:

    // 自定义数组大小public ArrayQueue(int capacity) {arr = new int[capacity + 1];}// 默认数组大小为: 10public ArrayQueue() {arr = new int[10];}
    @Override//判断是否为满队列(有很多种判断方法,这里使用牺牲空间方法来判断)public boolean isFull() {return (rear + 1) % arr.length == front;}

        3.8 用数组实现队列完整代码

public class ArrayQueue implements QueueInterface{private int front;private int rear;private int[] arr;// 自定义数组大小public ArrayQueue(int capacity) {arr = new int[capacity + 1];}// 默认数组大小为: 10public ArrayQueue() {arr = new int[10];}// 入队列@Overridepublic boolean offer(int e) {if (isFull()) {return false;}arr[rear] = e;rear = (rear+1) % arr.length;return true;}//出队列@Overridepublic int poll() {if (isEmpty()) {return -1;}int temp = arr[front];front = (front + 1) % arr.length;return temp;}//得到队头元素,不删除@Overridepublic int peek() {if (isEmpty()) {return -1;}return arr[front];}//得到队尾元素,不删除@Overridepublic int Rear() {if (isEmpty()) {return -1;}int temp = (rear == 0) ? arr.length - 1 : rear - 1;return arr[temp];}@Overridepublic boolean isEmpty() {return front == rear;}@Override//判断是否为满队列(有很多种判断方法,这里使用牺牲空间方法来判断)public boolean isFull() {return (rear + 1) % arr.length == front;}}

 

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

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

相关文章

9-1定义一个结构体计算该日是本年中的第几天。

#include<stdio.h> struct {int year;int month;int day; }date; int main(){int days;printf("输入年月日&#xff1a;\n");scanf("%d,%d,%d",&date.year,&date.month,&date.day);switch(date.month){case 1:daysdate.day; break;case…

【Element-ui】Checkbox 多选框 与 Input 输入框

文章目录 前言一、Checkbox 多选框1.1 基础用法1.2 禁用状态1.3 多选框组1.4 indeterminate 状态1.5 可选项目数量的限制1.6 按钮样式1.7 带有边框1.8 Checkbox Events1.9 Checkbox Attributes 二、Input 输入框2.1 基础用法2.2 禁用状态2.3 可清空2.4 密码框2.5 带 icon 的输入…

nexus私服开启HTTPS

maven3.8.1以上不允许使用HTTP服务的仓库地址&#xff0c;如果自己搭建的私服需要升级为HTTPS或做一些设置&#xff0c;如果要升级HTTPS服务有两种方式&#xff1a;1、使用Nginx开启HTTPS并反向代理nexus&#xff1b;2、直接在nexus开启HTTPS。这里介绍第二种方式 1、在ssl目录…

计算机网络的分类

目录 一、按照传输介质进行分类 1、有线网络 2、无线网络 二、按照使用者进行分类 1、公用网 (public network) 2、专用网(private network) 三、按照网络规模和作用范围进行分类 1、PAN 个人局域网 2、LAN 局域网 3、MAN 城域网 4、 WAN 广域网 5、Internet 因特…

ChatGPT 的 18 种玩法,你还不会用吗?

你确定&#xff0c;你会使用 ChatGPT 了吗&#xff1f; 今天给大家整理了 18 种 ChatGPT 的用法&#xff0c;看看有哪些方法是你能得上的。 用之前我们可以打开R5Ai平台&#xff0c;可以免费使用目前所有的大模型 地址&#xff1a;R5Ai.com 语法更正 用途&#xff1a;文章…

【vue】尚硅谷vue3学习笔记

Vue3快速上手 1.Vue3简介 2020年9月18日&#xff0c;Vue.js发布3.0版本&#xff0c;代号&#xff1a;One Piece&#xff08;海贼王&#xff09;耗时2年多、2600次提交、30个RFC、600次PR、99位贡献者github上的tags地址&#xff1a;https://github.com/vuejs/vue-next/release…

mysql(八)docker版Mysql8.x设置大小写忽略

Mysql 5.7设置大小写忽略可以登录到Docker内部&#xff0c;修改/etc/my.cnf添加lower_case_table_names1&#xff0c;并重启docker使之忽略大小写。但MySQL8.0后不允许这样&#xff0c;官方文档记录&#xff1a; lower_case_table_names can only be configured when initializ…

机器人与3D视觉 Robotics Toolbox Python 一 安装 Robotics Toolbox Python

一 安装python 库 前置条件需要 Python > 3.6&#xff0c;使用pip 安装 pip install roboticstoolbox-python测试安装是否成功 import roboticstoolbox as rtb print(rtb.__version__)输出结果 二 Robotics Toolbox Python样例程序 加载机器人模型 加载由URDF文件定义…

【算法每日一练]-图论(保姆级教程篇12 tarjan篇)#POJ3352道路建设 #POJ2553图的底部 #POJ1236校园网络 #缩点

目录 POJ3352&#xff1a;道路建设 思路&#xff1a; POJ2553&#xff1a;图的底部 思路&#xff1a; POJ1236校园网络 思路&#xff1a; 缩点&#xff1a; 思路&#xff1a; POJ3352&#xff1a;道路建设 由于道路要维修&#xff0c;维修时候来回都不能走&#xff0c;现要…

MDK提示:在多字节的目标代码中,没有此Unicode 字符可以映射到的字符

MDK警告提示在多字节的目标代码中&#xff0c;没有此Unicode 字符可以映射到的字符 警告提示&#xff1a; 在写MDK的工程代码时&#xff0c;发现代码中引入的头文件前方出现一些红色的叉叉&#xff0c;但是编译工程并不报错&#xff0c;功能也能正常执行的&#xff0c;只是提…

JS利用时间戳倒计时案例

我们在逛某宝&#xff0c;或者逛某东时&#xff0c;我们时常看到一个倒计时&#xff0c;时间一到就开抢&#xff0c;这个倒计时是如何做的呢&#xff1f;让我为大家介绍一下。 理性分析一下&#xff1a; 1.用将来时间减去现在时间就是剩余的时间 2.核心&#xff1a;使用将来的时…

C指针介绍(1)

文章目录 每日一言指针的简单介绍内存和地址指针在内存中的存储指针的定义和声明泛型指针 指针的关系运算算数运算关系运算 结语 每日一言 ⭐「 一声梧叶一声秋&#xff0c;一点芭蕉一点愁&#xff0c;三更归梦三更后。 」–水仙子夜雨-徐再思 指针的简单介绍 C语言指针是C语…

人工智能轨道交通行业周刊-第67期(2023.11.27-12.3)

本期关键词&#xff1a;列车巡检机器人、城轨智慧管控、制动梁、断路器、AICC大会、Qwen-72B 1 整理涉及公众号名单 1.1 行业类 RT轨道交通人民铁道世界轨道交通资讯网铁路信号技术交流北京铁路轨道交通网上榜铁路视点ITS World轨道交通联盟VSTR铁路与城市轨道交通RailMetro…

算法工程师面试八股(搜广推方向)

文章目录 机器学习线性和逻辑回归模型逻辑回归二分类和多分类的损失函数二分类为什么用交叉熵损失而不用MSE损失&#xff1f;偏差与方差Layer Normalization 和 Batch NormalizationSVM数据不均衡特征选择排序模型树模型进行特征工程的原因GBDTLR和GBDTRF和GBDTXGBoost二阶泰勒…

React使报错不再白屏

如果代码中出现问题导致报错&#xff0c;通常会使页面报错&#xff0c;导致白屏 function Head() {// 此时模拟报错导致的白屏return <div>Head --- {content}</div> } export default () > {return (<><div>下面是标题</div><Head />…

若依框架分页

文章目录 一、分页功能解析1.前端代码分析2.后端代码分析3. LIMIT含义 二、自定义MyPage,多态获取total1.定义MyPage类和对应的调用方法 一、分页功能解析 1.前端代码分析 页面代码 封装的api请求 接口请求 2.后端代码分析 controller代码 - startPage() getDataTable(…

yolo.txt格式与voc格式互转,超详细易上手

众所周知,yolo训练所需的标签文件类型是.txt的,但我们平时使用标注软件(labelimage等)标注得到的标签文件是.xml类型的,故此xml2txt之间的转换就至关重要了,这点大家不可能想不到,但是网上的文章提供的代码大多数都是冗余,或者难看,难以上手,故此作者打算提供一个相对…

Sharding-Jdbc(3):Sharding-Jdbc分表

1 分表分库 LogicTable 数据分片的逻辑表&#xff0c;对于水平拆分的数据库(表)&#xff0c;同一类表的总称。 订单信息表拆分为2张表,分别是t_order_0、t_order_1&#xff0c;他们的逻辑表名为t_order。 ActualTable 在分片的数据库中真实存在的物理表。即上个示例中的t_…

怎样使用rtsp,rtmp摄像头低延时参于Web视频会议互动直播

业务系统中有大量的rtsp&#xff0c;rtmp等监控直播设备&#xff0c;原大部分都是单一业务监控直播之类&#xff0c;目前很多业务需要会议互动&#xff0c;需要监控参会&#xff0c;提出需摄像头拉流参会的需求&#xff0c;由于rtmp&#xff0c;rtsp原生不支持web播放&#xff…

vue3-在自定义hooks使用useRouter 报错问题

文章目录 前言一、报错分析报错的Vue warn截图&#xff1a;查看文档 二、那么在hook要怎么引入路由呢&#xff1f; 前言 记录在vue3项目中&#xff0c;hook使用useRouter 报错问题 一、报错分析 报错的Vue warn截图&#xff1a; 警告 inject() can only be used inside setup…