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++

代码如下:

    //入列
    @Override
    public 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-- 。最后,返回出栈节点的数值即可。

代码如下:

 

    //出列
    @Override
    public 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 或者抛异常处理当队列不为空时,直接返回头部节点的值即可

代码如下:

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

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

                直接返回 size 即可。

    @Override
    public int size() {
        return size;
    }

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

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

代码如下:

    @Override
    public 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;

    //入列
    @Override
    public 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;
    }

    //出列
    @Override
    public 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;
    }

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

    @Override
    public int size() {
        return size;
    }

    @Override
    public 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,这样就可以数组中循环走了。在入队前,需要先判断是否为满队列了。

代码如下:

    // 入队列
    @Override
    public 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 处理。

代码如下:

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

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

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

代码如下:

    //得到队头元素,不删除
    @Override
    public 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]

代码如下:

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

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

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

代码如下:

    @Override
    public 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];
    }

    // 默认数组大小为: 10
    public 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];
    }

    // 默认数组大小为: 10
    public ArrayQueue() {
        arr = new int[10];
    }

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

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

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

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

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

    @Override
    //判断是否为满队列(有很多种判断方法,这里使用牺牲空间方法来判断)
    public boolean isFull() {
        return (rear + 1) % arr.length == front;
    }
    
}

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

机器学习笔记 - 什么是3D语义场景完成/补全?

一、什么是3D语义场景补全? 3D 语义场景完成(Semantic Scene Completion)是一种机器学习任务,涉及以体素化形式预测给定环境的完整3D场景(完成3D形状的同时推断场景的 3D 语义分割的任务)。这是通过使用深度图和为场景提供上下文的可选 RGB 图像来完成的。目标是以一种可轻…

2023年腾讯云双12优惠活动整理汇总

2023年双12腾讯云推出了年末感恩回馈活动,年度爆款2核2G4M云服务器118元/年,新老用户同享,还可领取总面值2000元代金券,老用户服务器续费4折起。本文为大家整理汇总腾讯云双12优惠活动。 活动地址: 点此直达腾讯云双1…

linux常用命令-find命令与scp命令详解(超详细)

文章目录 前言一、find命令介绍1. find命令简介2. find命令的基本语法3. 常用的find命令选项和表达式 二、find命令示例用法1. 按照名称进行搜索2. 按照类型进行搜索3. 按照修改时间进行搜索4. 按照文件大小进行搜索5. 对搜索到的文件执行指定的命令6. 删除搜索到的文件 三、sc…

23种设计模式之C++实践(二)

23种设计模式之C++实践 3. 设计模式(二)组合型模式7. 适配器模式——不兼容结构的协调7.2:类适配器模式7.3:双向适配器模式适配器模式总结8.桥接模式——处理多维度变化桥接模式总结9. 组合模式——树形结构的处理9.2 透明组合模式9.3 安全组合模式组合模式总结10. 装饰模式…

yolov5 7.0版本部署手机端。通过pnnx导出ncnn。

yolov5 7.0版本部署手机端。通过pnnx导出ncnn。 流程配置ncnn android yolov5导出自己模型的ncnn修改yolo.py文件导出TorchScript文件pnnx转torchscript为ncnn 安卓运行权重路径输入输出anchors 大小类别名generate_proposals方法修改 结果 流程 网络yolov5 的部署已经有很多了…

分享一个国内可用的免费GPT4-AI提问AI绘画网站工具

一、前言 ChatGPT GPT4.0,Midjourney绘画,相信对大家应该不感到陌生吧?简单来说,GPT-4技术比之前的GPT-3.5相对来说更加智能,会根据用户的要求生成多种内容甚至也可以和用户进行创作交流。 然而,GPT-4对普…

Elasticsearch 优化查询中获取字段内容的方式,性能提升5倍!

1、背景 集群配置为:8 个 node 节点,16 核 32G,索引 4 分片 1 副本。应用程序的查询逻辑是按经纬度排序后找前 200 条文档。 1、应用对查询要求比较高,search 没有慢查询的状态。 2、集群压测性能不能上去,cpu 使用未打…

mybatis的一级缓存和二级缓存

mybatis的一级缓存和二级缓存 mybatis设计两级缓存来提高查询效率。 一级缓存是SqlSession级别,每个会话都需要创建一个sqlsession,避免同一个用户在多次查询中每次都去查询数据库就把查询结果做了缓存 二级缓存 跨SqlSession的缓存,以及缓存…

C#——Delegate(委托)与Event(事件)

C#——Delegate(委托)与Event(事件) 前言一、Delegate(委托)1.是什么?2.怎么用?Example 1:无输入无返回值Example 2:有输入Example 3:有返回值Exa…

抖音外卖商品模型

目录 一、抖音外卖商品模型 二、商家运营流程 (一)商家入驻流程 (二)商品发布流程 三、推广带货流程 (一)短视频带货 (二)直播视频带货 【直播工具】 【直播流程】 直播前…

SQL Server 数据库,创建数据表(使用T-SQL语句)

2.3表的基本概念 表是包含数据库中所有数据的数据库对象。数据在表中的组织方式与在电子表格中相似,都是 按行和列的格式组织的,每行代表一条唯一的记录,每列代表记录中的一个字段.例如,在包含公 司员工信息的表中,每行…

数据结构:图文详解双向链表的各种操作(头插法,尾插法,任意位置插入,查询节点,删除节点,求链表的长度... ...)

目录 一.双向链表的概念 二.双向链表的数据结构 三.双向链表的实现 节点的插入 头插法 尾插法 任意位置插入 节点的删除 删除链表中第一次出现的目标节点 删除链表中所有与关键字相同的节点 节点的查找 链表的清空 链表的长度 四.模拟实现链表的完整代码 前言&am…

初探Java之旅:探寻Java的奥秘

✨个人主页:全栈程序猿的CSDN博客 💨系列专栏:Java从入门到精通 ✌座右铭:编码如诗,Bug似流星,持续追求优雅的代码,解决问题如同星辰般自如 在计算机编程的世界中,有一门被誉为“千变…

位图布隆过滤器(附面试题)

文章目录 目录 文章目录 前言 一 . 位图 1.1 面试题 1.2 位图概念 1.3 位图的实现 1.4 位图的应用 二 . 布隆过滤器 2.1 布隆过滤器提出 2.2布隆过滤器概念 2.3 布隆过滤器的查找 2.4 实现 2.5 布隆过滤器删除 2.6 布隆过滤器优点 2.7 布隆过滤器缺陷 2.8 布隆过滤器使用场景 三…

面试官:说说Vue中Proxy与Object.defineProperty的用法与区别

前言 面试时,我们说完Vue响应式原理,或者Vue2和Vue3的区别时,通常会引出Vue3使用了Proxy来优化响应式,而面试官会继续深挖:说说Proxy与Object.defineProperty的区别。 我们不能只说Proxy直接代理一个对象&#xff0c…

【java毕业设计源码】基于SSM框架的在线智能题库管理系统设计与实现

该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程等学习内容。 目录 一、项目介绍: 二、文档学习资料: 三、模块截图: 四、开发技术与运行环境: 五、代码展示: 六、数据库表截图&#xff1a…

【论文阅读 + 核心代码定位解读】(2023 AAAI)HiCLR

Hierarchical Consistent Contrastive Learning for Skeleton-Based Action Recognition with Growing Augmentations Contribution 直接使用 strong augmentations 会导致图片/骨架点序列的结构变形和语义信息损失,从而导致训练过程的不稳定。于是本文提出了一种逐…

Java Servlet

请求 请求行 方式 uri http/1.1 请求头 请求体 form表单标签提交Get请求时,参数以键值对形式放在url后,不放在请求体里,Get方式的请求也是可以有请求体的 Post请求时,放在请求头里面 Servlet (server applet) 是运行在服务端…

curl --compressed报错,此版本不支持此命令

出现这个问题是因为微软windows自带的curl不支持这个选项,验证如下 执行where curl 时,可以看到输出为 C:\Windows\System32\curl.ee 解决方法是使用其它curl,下载地址如下 curl for Windows https://curl.se/windows/ 然后把安装目录的bin目录放到path环境变量里最开始, 让…

基于微信小程序的高校活动系统

1 前言 1.1开发背景及意义 高校课余活动管理是中职学生素质教育的重要途径及有效方式,特别是对于一个院校的校园文化建设、校风学风建设和学生综合素质方面的提高至关重要t叫"。良好的学生活动组织可以更好地调动学生参与活动,让学生展示自己的能力…