数据结构 之 队列(Queue)

news2025/3/12 22:39:34
​​​​​​​

🎉欢迎大家观看AUGENSTERN_dc的文章(o゜▽゜)o☆✨✨

🎉感谢各位读者在百忙之中抽出时间来垂阅我的文章,我会尽我所能向的大家分享我的知识和经验📖

🎉希望我们在一篇篇的文章中能够共同进步!!!

🌈个人主页:AUGENSTERN_dc

🔥个人专栏:C语言 | Java | 数据结构

⭐个人格言:

一重山有一重山的错落,我有我的平仄

一笔锋有一笔锋的着墨,我有我的舍得

目录

1. 定义:

2. 队列的常用方法和模拟实现:

2.1 常用方法:

2.2 模拟实现:

 3. 队列的模拟实现源码:

4. 循环队列

4.1 模拟实现:

5. 双端队列:


1. 定义:

队列和栈类似,是一种只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表;

进入队列的一端称为队尾,离开队列的一端称为队头

队列这个结构遵循先进先出的原则;

 在日常生活中,例如:

多人在网上对老师提交任务时,会将我们所提交的任务存放到一个队列中,然后队列将这些任务按照先进先出的顺序进行出队和入队的操作,老师看到的任务,也就会按照提交时间的先后来排序;
 

由上图可以看出Queue是一个接口,底层是由链表(LinkedList)实现的;

2. 队列的常用方法和模拟实现:

2.1 常用方法:

方法作用
offer(E e)将e进行入队操作
E poll()

将e进行出队列操作,并且返回e的值

E peek()获取队头元素
int size()获取队列的长度
boolean isEmpty()判断队列是否为空

(在队列的模拟实现中,我们并不使用泛型,而是使用整形来代替泛型) 

以上就是队列的常用方法,接下来我们进行模拟实现:

2.2 模拟实现:

队列的底层是由链表来实现的,我们先创建一个My_Queue类:

public class My_Queue {
    public static class ListNode {
        ListNode next;      //节点的后继
        ListNode prev;      //节点的前驱
        int value;          //节点的值

        public ListNode() {
            //不带参数的构造方法
        }
        public ListNode(int value){
            //带一个参数的构造方法,将节点的值赋为value
            this.value = value;
        }
    }

    ListNode first;         //队头节点
    ListNode last;          //队尾节点
    int size = 0;           //队列长度
}

< 1 > offer方法:

offer方法是将指定元素插入到队列的队尾:

与之前的栈和顺序表不同,由于队列的底层是用链表实现的,故不需要判断队列是否满了;

// 入队列---向双向链表位置插入新节点
    public void offer(int e){
        ListNode newNode = new ListNode(e);     //实例化一个节点
        if(first == null){                      //若该队列为空
            first = newNode;                    //将队头和队尾都更新为newNode
            last = newNode;
        }else{                                  //若队列不为空
            last.next = newNode;                //将newNode赋值给队尾.next
            newNode.prev = last;                //将newNode的pre赋值为队尾
            last = newNode;                     //将队尾更新为newNode
        }
        last = newNode;                         //更新队尾
        size++;                                 //队列长度 +1
}

< 2 > poll方法:

poll方法是将队头的元素进行出队操作,并返回队头元素的值:

在进行该操作之前,我们需要判断队列是否为空,若为空,则需抛出异常:

异常代码如下:

public class QueueEmptyException extends RuntimeException {
    public QueueEmptyException () {
        super();
    }

    public QueueEmptyException (String str) {
        super(str);
    }
}

poll方法如下:

public int poll(){
        // 1. 队列为空
        // 2. 队列中只有一个元素----链表中只有一个节点---直接删除
        // 3. 队列中有多个元素---链表中有多个节点----将第一个节点删除
        int value = 0;
        if(first == null){      //若为空,则抛出异常
            throw new QueueEmptyException("队列为空,不能进行poll操作!!!");
        }else if(first == last){        //若只有一个节点,则直接删除该节点
            last = null;
            first = null;
        }else{
            value = first.value;        //将队头的元素赋值给value
            first = first.next;         //将队头更新为队头的下一个节点
            first.prev.next = null;
            first.prev = null;
        }
        size--;                         //将队列长度 -1
        return value;                   //返回队头的值
}

< 3 > peek方法:

peek方法是返回队头的节点的值:

// 获取队头元素---获取链表中第一个节点的值域
    public int peek(){
        if(first == null){      //若队列为空,则抛出异常
            throw new QueueEmptyException("队列为空,不能进行peek操作!!!");
        }
        return first.value;     //返回队头的值
}

< 4 > size方法:

size方法是返回队列的长度:

public int size() {
        return size;        //返回队列的长度
}

< 5 > isEmpty方法:

isEmpty是判断队列是否为空:

public boolean isEmpty(){
        return first == null;       //返回队头是否为空 的值
}

 3. 队列的模拟实现源码:

public class My_Queue {
    public static class ListNode {
        ListNode next;      //节点的后继
        ListNode prev;      //节点的前驱
        int value;          //节点的值

        public ListNode() {
            //不带参数的构造方法
        }
        public ListNode(int value){
            //带一个参数的构造方法,将节点的值赋为value
            this.value = value;
        }
    }

    ListNode first;         //队头节点
    ListNode last;          //队尾节点
    int size = 0;           //队列长度

    // 入队列---向双向链表位置插入新节点
    public void offer(int e){
        ListNode newNode = new ListNode(e);     //实例化一个节点
        if(first == null){                      //若该队列为空
            first = newNode;                    //将队头和队尾都更新为newNode
            last = newNode;
        }else{                                  //若队列不为空
            last.next = newNode;                //将newNode赋值给队尾.next
            newNode.prev = last;                //将newNode的pre赋值为队尾
            last = newNode;                     //将队尾更新为newNode
        }
        last = newNode;                         //更新队尾
        size++;                                 //队列长度 +1
    }

    // 出队列---将双向链表第一个节点删除掉
    public int poll(){
        // 1. 队列为空
        // 2. 队列中只有一个元素----链表中只有一个节点---直接删除
        // 3. 队列中有多个元素---链表中有多个节点----将第一个节点删除
        int value = 0;
        if(first == null){      //若为空,则抛出异常
            throw new QueueEmptyException("队列为空,不能进行poll操作!!!");
        }else if(first == last){        //若只有一个节点,则直接删除该节点
            last = null;
            first = null;
        }else{
            value = first.value;        //将队头的元素赋值给value
            first = first.next;         //将队头更新为队头的下一个节点
            first.prev.next = null;
            first.prev = null;
        }
        size--;                         //将队列长度 -1
        return value;                   //返回队头的值
    }

    // 获取队头元素---获取链表中第一个节点的值域
    public int peek(){
        if(first == null){      //若队列为空,则抛出异常
            throw new QueueEmptyException("队列为空,不能进行peek操作!!!");
        }
        return first.value;     //返回队头的值
    }

    public int size() {
        return size;        //返回队列的长度
    }

    public boolean isEmpty(){
        return first == null;       //返回队头是否为空 的值
    }
}

4. 循环队列

实际中我们有时还会使用一种队列叫循环队列。如操作系统课程讲解生产者消费者模型时可以就会使用循环队列。 环形队列通常使用数组实现。

4.1 模拟实现:

/*
    解题思路:
    1. 注意,循环队列底层空间大小是固定的
    2. 采用计数方式实现队列空或者满的判断
    3. 入队列时:队列可能满,往队尾插入,注意back在末尾特殊情况
    4. 出队列时:队列可能空,删除队头元素,注意front可能在队尾
    5. 获取队头注意空队列时返回-1
    6. 获取队尾时,注意back-1可能为负数,队尾元素下标:
       (back-1+array.length)%array.length
*/
class MyCircularQueue {
    int[] array;
    int front;   // 队头
    int back;    // 队尾
    int count;   // 队列中有效元素个数
    public MyCircularQueue(int k) {
        array = new int[k];
    }
    
    public boolean enQueue(int value) {
        if(isFull()){
            return false;
        }

        // 在队尾插入一个元素,然后back往后移动
        array[back] = value;
        back++;

        // back往后移动之后,可能会来到空间末尾
        // 此时将back挪到空间起始位置
        if(back == array.length){
            back = 0;
        }

        count++;
        return true;
    }
    
    public boolean deQueue() {
        if(isEmpty()){
            return false;
        }

        // 出队列,队头往后移动
        ++front;

        // 队头往后移动之后也可能会来到空间末尾
        // 此时需要挪到空间起始位置
        front %= array.length;
        --count;
        return true;
    }
    
    public int Front() {
        if(isEmpty()){
            return -1;
        }

        // 如果队列不空,说明队列中有元素,队头元素直接返回front即可
        return array[front];
    }
    
    public int Rear() {
        if(isEmpty()){
            return -1;
        }

        // 如果队列不空,说明队列中有元素
        // 队尾元素即:back-1,
        // 如果back不在0号位置,back-1就是队尾元素下标
        // 如果back在0号位置,-1之后就是负数,因此需要+数组长度
        // 两个结合起来:
        return array[(back - 1 + array.length)%array.length];
    }
    
    public boolean isEmpty() {
        return 0 == count;
    }
    
    public boolean isFull() {
        return count == array.length;
    }
}

5. 双端队列:

双端队列(deque)是指允许两端都可以进行入队和出队操作的队列,deque 是 “double ended queue” 的简称。 那就说明元素可以从队头出队和入队,也可以从队尾出队和入队。

Deque是一个接口,使用时必须创建LinkedList的对象。

以上就是队列的全部内容:感谢观看!!!!

制作不易,三连支持

谢谢!!!

以上的模拟实现代码未必是最优解,仅代表本人的思路,望多多理解,谢谢!!

最后送给大家一句话,同时也是对我自己的勉励:

知不足而奋进,望远山而前行!!!!

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

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

相关文章

双指针算法_移动零_

题目&#xff1a; 给定一个数组 num &#xff0c;编写一个函数将数组内部的数字0都移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序&#xff01; 同时不能通过复制数组&#xff0c;开辟新的数组空间的情况下原地对数组进行操作 示例&#xff1a; 本题的原理&#x…

掘根宝典之C++普通迭代器和反向迭代器详解

简介 迭代器是一种用于遍历容器元素的对象。它提供了一种统一的访问方式&#xff0c;使程序员可以对容器中的元素进行逐个访问和操作&#xff0c;而不需要了解容器的内部实现细节。 C标准库里每个容器都定义了迭代器&#xff0c;这迭代器的名字就叫容器迭代器 迭代器的作用类…

谷歌浏览器运行vue项目。 控制台打印cjs.js,如何解决

当浏览器运行vue项目。 控制台打印cjs.js&#xff0c;如何解决 &#xff1a;

oracle基础-子查询 备份

一、什么是子查询 子查询是在SQL语句内的另外一条select语句&#xff0c;也被称为内查询活着内select语句。在select、insert、update、delete命令中允许是一个表达式的地方都可以包含子查询&#xff0c;子查询也可以包含在另一个子查询中。 【例1.1】在Scott模式下&#xff0…

Java项目企业设备管理系统

java项目企业设备管理系统javaweb项目ssm框架项目 运行环境:idea/eclipse tomcat jdk mysql navicat 系统用户分为员工和管理员两类用户。两类用户都可以进行系统的登录&#xff0c;虽然进入的系统主页结构相似&#xff0c;但是在功能上有不同。员工的密码可以自己进入系统后…

DirectShowPlayerService::doSetUrlSource: Unresolved error code 0x800c000d

报出这个问题&#xff0c;应该是对给的url解析不正确&#xff0c;我给的是rtsp的视频流地址&#xff0c;应该是对该格式解析异常。 所以参考两篇文&#xff1a; QT无法播放视频&#xff1a;报错&#xff1a;DirectShowPlayerService::doRender: Unresolved error code 0x8004…

2024年3月16日云仓酒庄广西发布会圆满举行

原标题&#xff1a;云仓酒庄广西发布会圆满举行&#xff0c;致敬经销商团队共谋未来发展 2024年3月16日&#xff0c;备受瞩目的云仓酒庄广西发布会在广西南宁隆重举行。此次发布会旨在感谢广西地区经销商团队的长期支持&#xff0c;并共同推进未来发展蓝图。活动现场氛围热烈&…

总要有一次,为自己疯狂

机会其实不多 最近一口气看了《飞驰人生》以及《飞驰人生2》&#xff0c;过去是以看喜剧的心态去看沈腾的电影&#xff0c;当如今二刷时发现这不就是生活吗&#xff0c;只不过用喜剧的外壳做了层包装。两部电影给我影响最深的就是最后的那段对白&#xff0c;“张弛&#xff0c…

【大模型系列】统一图文理解与生成(BLIP/BLIPv2/InstructBLIP)

文章目录 1 BLIP(2022, Salesforce Research)1.1 简介1.2 数据角度1.3 模型角度1.4 BLIP预训练的目标 2 BLIP2(ICML2023, Salesforce)2.1 简介2.2 模型架构2.3 训练细节 3 InstructBLIP(2023, Salesforce)3.1 指令微调技术(Instruction-tuning)3.2 数据集准备3.3 Instruction-a…

数据结构——动态顺序表

数据结构的动态顺序表有以下几个操作&#xff1a;创建&#xff0c;销毁&#xff0c;初始化&#xff0c;增删查改和打印以及内存空间不够时的扩容 本文的宏定义&#xff1a; #define SeqTypeData int 1.动态顺序表的创建 typedef struct SeqListInit{//动态顺序表的创建SeqT…

双指针算法_复写零

题目&#xff1a; 给一个固定长度的数组arr&#xff0c;将数组中出现的每一个0都复写一遍&#xff0c;并且将其余元素都往右移动 且不要再超过数组长度的位置写入元素&#xff0c;在数组上直接修改 示例&#xff1a; 双数组模拟操作&#xff1a; 从示例来看&#xff0c;因为…

【状态压缩DP】第十三届蓝桥杯省赛C++ B组《积木画》(C++)

【题目描述】 小明最近迷上了积木画&#xff0c;有这么两种类型的积木&#xff0c;分别为 I 型&#xff08;大小为 2 个单位面积&#xff09;和 L 型&#xff08;大小为 3 个单位面积&#xff09;&#xff1a; 同时&#xff0c;小明有一块面积大小为 2N 的画布&#xff0c;画布…

模板进阶:非类型模板参数,特化

一、非类型模板参数 非类型模板参数&#xff0c;就是用一个常量作为 类/函数 的模板参数&#xff0c;在 类/函数 中可以被当成常量使用。 template<class T, size_t N>// N 为一个非类型模板参数 class Stack { public:Stack(){_a new T[N];} protected:T* _a; };int m…

腾讯云服务器入站规则端口开放使用指南(CentOS系统)

第一步&#xff1a;开放安全组入站规则 来源处0.0.0.0/0是对IPv4开发&#xff0c;::/0是对IPv6开放&#xff1b; 协议端口按照提示填写即可。云服务器防火墙开放 第三步&#xff1a;本地防火墙开放 sudo firewall-cmd --zonepublic --add-port你的端口号/tcp --perma…

RTT——stm32f103的can总线通信

1.创建工程 2.配置时钟和引脚 引脚配置使能CAN 时钟配置&#xff0c;采用外部高速时钟 生成MDK工程后复制相关初始化函数到RTT-studio中 将void HAL_CAN_MspInit(CAN_HandleTypeDef* canHandle)函数复制至broad.c文件中 将时钟配置函数复制到drv_clk.c中&#xff0c;只复制函数…

Java8中Stream流API最佳实践Lambda表达式使用示例

文章目录 一、创建流二、中间操作和收集操作筛选 filter去重distinct截取跳过映射合并多个流是否匹配任一元素&#xff1a;anyMatch是否匹配所有元素&#xff1a;allMatch是否未匹配所有元素&#xff1a;noneMatch获取任一元素findAny获取第一个元素findFirst归约数值流的使用中…

Linux下的多线程编程:原理、工具及应用(2)

&#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;Flower of Life—陽花 0:34━━━━━━️&#x1f49f;──────── 4:46 &#x1f504; ◀️ ⏸ ▶️ ☰ …

【C++ RB树】

文章目录 红黑树红黑树的概念红黑树的性质红黑树节点的定义红黑树的插入代码实现总结 红黑树 AVL树是一颗绝对平衡的二叉搜索树&#xff0c;要求每个节点的左右高度差的绝对值不超过1&#xff0c;这样保证查询时的高效时间复杂度O( l o g 2 N ) log_2 N) log2​N)&#xff0c;…

钉钉小程序 - - - - - 如何通过一个链接打开小程序内的指定页面

方式1 钉钉小程序 scheme dingtalk://dingtalkclient/action/open_mini_app?miniAppId123&pagepages%2Findex%2Findex%3Fx%3D%25E4%25B8%25AD%25E6%2596%2587 方式2 https://applink.dingtalk.com/action/open_mini_app?type2&miniAppIdminiAppId&corpIdcorpId&…

MySQL行锁核心知识介绍

MySQL的行锁是数据库中用于控制并发访问的一种机制。它允许在数据库的行级别上实现锁定&#xff0c;从而允许多个事务同时修改不同行的数据&#xff0c;而不会相互干扰。这种锁机制可以提高数据库的并发性能&#xff0c;减少锁争用&#xff0c;提高事务的吞吐量。在本教程中&am…