队列(Queue),循环队列,双端队列(Deque)and LeetCode刷题

news2024/9/22 11:29:18

队列(Queue),循环队列,双端队列(Deque)and LeetCode刷题

  • 1. 队列的概念
  • 2.队列的使用
  • 3. 队列的模拟实现
    • 3.1 用链式结构实现队列
    • 3.2 用顺序结构实现队列
  • 4. 循环队列
  • 5. 双端队列(Deque)
  • 6. LeetCode刷题
    • 6.1 用队列实现栈
    • 6.2 用栈实现队列

1. 队列的概念

什么是队列?打个比方,就是一群人在排队买东西,先排队的人先拿到东西先离开,后排队的人后拿到东西后离开。

因此,队列是一种 只允许在一端进行插入数据操作,在另一端进行删除数据操作 的特殊线性表,即 “先进先出” ,而栈是“先进后出”。其中,进行插入操作的一端称为队尾(Tail/Rear),该操作叫做入队; 进行删除操作的一端称为队头(Head/Front),该操作叫做出队。在使用队列时,可以画出这样的图形

在这里插入图片描述

2.队列的使用

Queue是一个 接口 ,底层是 由LinkedList实现 的!

Queue里的方法是比较少的,如图:
在这里插入图片描述
其中,红色框框里的是一组,橙色框框里的是一组;两组的方法都差不多,一般情况下用的是红色框框里的方法

  • offer(E):boolean 入列
  • poll():E 出列
  • peek():E获取队头元素

另外,Queue继承于Collection接口里的两个方法也比较常用:

  • size():int 获取队列元素个数
  • isEmpty():boolean 判断队列是否为空

在这里插入图片描述

public class Test {
    public static void main(String[] args) {
        Queue<Integer> queue = new LinkedList<>();
        queue.offer(1);
        queue.offer(2);
        queue.offer(3);
        queue.offer(4);
        queue.offer(5);
        System.out.println(queue.poll());//1
        System.out.println(queue.size());//4
        System.out.println(queue.peek());//2
        System.out.println(queue.isEmpty());//false
    }
}

注意: Queue是接口,不能进行实例化接口,而是实例化LinkedList对象,因为LinkedList实现了Queue接口!

3. 队列的模拟实现

常见的结构有顺序结构链式结构,那么我们模拟实现队列时,选用什么结构来实现呢?答案是都是可以的!

3.1 用链式结构实现队列

链式结构包括单链表和双链表,两种都是可以用来实现的

  • 假如用单链表来实现,为了使时间复杂度更小,必须要采用头删和尾插,并且需要一个tail引用来标记尾节点,当然也需要head来标记头节点
  • 假如用双链表来实现的话,那就灵活多了,既可以用头删和尾插来模拟实现出队和入队,也可以使用尾删和头插!

下面仅用双链表来模拟实现

public class MyQueue {

    static class ListNode {
        public int val;
        public ListNode prev;
        public ListNode next;

        public ListNode(int val) {
            this.val = val;
        }
    }

    public ListNode first = null;
    public ListNode last = null;

    public int usedSize = 0;

    public void offer(int val) {
        ListNode node = new ListNode(val);
        if(first == null) {
            first = last = node;
        }else {
            node.prev = last;
            last.next = node;
            last = node;
        }
        usedSize++;
    }

    public int poll() {
        if(first == null) {
            return -1;
        } else {
            int ret = first.val;
            first = first.next;
            if(first != null){
                first.prev = null;
            }
            usedSize--;
            return ret;
        }
    }

    public int peek() {
        if(first == null) {
            return -1;
        } else {
            return first.val;
        }
    }

    public boolean isEmpty() {
        return usedSize == 0;
    }
}

3.2 用顺序结构实现队列

如果使用数组去实现队列,当出队列后,要么把所有的元素都往前挪一位,然而这很浪费时间;要么就要浪费空间,当有大量的出队操作时,就会浪费大量的空间,简直是得不偿失!

那有什么办法可以解决这些问题呢?我们假如可以把数组的首尾连起来,构成循环,出队操作可以直接将队头往后挪一个位置,而原来的位置又能被后面的入队元素占据,这样既能节省时间,又不会浪费空间,接下来就来学习一下循环队列

4. 循环队列

环形队列通常使用数组实现

如图,在一个长度为8的循环队列中,存放12、23、34、45、56元素,用front标记队头,用rear标记队尾,注意rear是数组中最后一个有效元素的下一个

在这里插入图片描述
内圈表示数组的下标,外圈表示数组存放的元素。构建好基本的框架后,问题来了

问题1: 如何判空和判满

判空:只要front和rear相遇,就是空
判满:

  • 方式1:定义一个变量usedSize,表示当前数组中存放有效数据的个数
  • 方式2:添加标记,定义一个boolean类型的标记
  • 方式3:浪费一个空间,每次添加元素时判断rear的下一个是不是front,若是则已满

在这里插入图片描述
如图,利用方式3,则该循环队列已满,因为rear的下一位是front。该方式浪费了一个空间

问题2: rear或front下标如何由7位置到0位置?可以利用如下公式:(rear + 1) % arr.length

废话不多说,直接上链接来用顺序结构来实现队列,题目链接:622. 设计循环队列

采用方式1的代码如下:

class MyCircularQueue {
    public int[] elem;
    public int front;
    public int rear;
    public int usedSize;

    public MyCircularQueue(int k) {
        elem = new int[k];
    }
    
    public boolean enQueue(int value) {
        if(isFull()) {
            return false;
        }
        elem[rear] = value;
        rear = (rear+1) % elem.length;
        usedSize++;
        return true;
    }
    
    public boolean deQueue() {
        if(isEmpty()) {
            return false;
        }
        front = (front+1) % elem.length;
        usedSize--;
        return true;
    }
    
    public int Front() {
        if(isEmpty()) {
            return -1;
        }
        return elem[front];
    }
    
    public int Rear() {
        if(isEmpty()) {
            return -1;
        }
        int index = rear == 0? elem.length-1 : rear-1;
        return elem[index];
    }
    
    public boolean isEmpty() {
        if(usedSize == 0) {
            return true;
        }
        return false;
    }
    
    public boolean isFull() {
        if(usedSize == elem.length) {
            return true;
        }
        return false;
    }
}

5. 双端队列(Deque)

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

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

在实际工程中,使用Deque接口是比较多的,栈和队列均可以使用该接口

    Deque<Integer> stack = new ArrayDeque<>();//双端队列的线型实现
    Deque<Integer> queue = new LinkedList<>();//双端队列的链式实现

6. LeetCode刷题

6.1 用队列实现栈

题目链接:225. 用队列实现栈

解题思路:

  1. 创建两个队列,当进行模拟栈的pop操作时,元素会从其中的一个队列转移到另外一个队列,两个队列交替来存放所有元素
  2. 没有进行操作时,如果要实现的栈不为空,始终只有一个队列存有元素,另外一个队列为空
  3. push操作:将元素放入非空队列中,若都是空对列则放入第一个队列中
  4. pop操作:将非空队列中的元素依次放入另外一个队列中,只有最后一个元素出队
  5. top操作与pop操作大同小异

代码如下:

class MyStack {
    public Queue<Integer> q1;
    public Queue<Integer> q2;

    public MyStack() {
        q1 = new LinkedList<>();
        q2 = new LinkedList<>();
    }
    
    public void push(int x) {
        if(!q1.isEmpty()) {
            q1.offer(x);
        }else if(!q2.isEmpty()) {
            q2.offer(x);
        }else {
            q1.offer(x);
        }
    }
    
    public int pop() {
        if(empty()) {
            return -1;
        }
        if(!q1.isEmpty()) {
            int size = q1.size();
            for(int i = 0; i < size-1; i++) {
                q2.offer(q1.poll());
            }
            return q1.poll();
        }else {
            int size = q2.size();
            for(int i = 0; i < size-1; i++) {
                q1.offer(q2.poll());
            }
            return q2.poll();
        }
    }
    
    public int top() {
        if(empty()) {
            return -1;
        }
        if(!q1.isEmpty()) {
            int size = q1.size();
            for(int i = 0; i < size-1; i++) {
                q2.offer(q1.poll());
            }
            int val = q1.peek();
            q2.offer(q1.poll());
            return val;
        }else {
            int size = q2.size();
            for(int i = 0; i < size-1; i++) {
                q1.offer(q2.poll());
            }
            int val = q2.peek();
            q1.offer(q2.poll());
            return val;
        }
    }
    
    public boolean empty() {
        return q1.isEmpty() && q2.isEmpty();
    }
}

6.2 用栈实现队列

题目链接:232. 用栈实现队列

解题思路:

  1. 创建两个栈,其中一个栈s1专门用来入队,另外一个栈专门用来出队
  2. 入队时,将元素添加进栈s1中
  3. 出队时,判断栈s2是否为空,若为空则将s1中的全部元素依次都添入s2中,再将s2中的栈顶元素弹出;若s2不为空则直接将s2中的栈顶元素直接弹出

代码如下:

class MyQueue {
    public Stack<Integer> s1;
    public Stack<Integer> s2;

    public MyQueue() {
        s1 = new Stack<>();
        s2 = new Stack<>();
    }
    
    public void push(int x) {
        s1.push(x);
    }
    
    public int pop() {
        if(s2.isEmpty()) {
            while(!s1.isEmpty()) {
                s2.push(s1.pop());
            }
        }
        return s2.pop();
    }
    
    public int peek() {
        if(s2.isEmpty()) {
            while(!s1.isEmpty()) {
                s2.push(s1.pop());
            }
        }
        return s2.peek();
    }
    
    public boolean empty() {
        return s1.isEmpty() && s2.isEmpty();
    }
}

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

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

相关文章

探索AI播客:PocketPod——定制化音频内容的未来引领者

在数字内容日新月异的今天,从文字、图片到视频、音乐,每一种媒介形式都在不断进化,以满足人们日益增长的多元化需求。而现在,一个全新的领域正蓄势待发——AI生成的播客内容,正由创新先锋PocketPod平台引领,为音频世界带来前所未有的变革。 一、产品概览:PocketPod——…

百度网盘Android一二面凉经(2024)

百度网盘Android一二面凉经(2024) 笔者作为一名双非二本毕业7年老Android, 最近面试了不少公司, 目前已告一段落, 整理一下各家的面试问题, 打算陆续发布出来, 供有缘人参考。今天给大家带来的是《百度网盘Android一二面凉经(2024)》。 面试职位: 网盘主端研发组_Android高级研…

Spring Data Jpa 原生SQL联表查询返回自定义DTO

Spring Data Jpa 原生SQL联表查询返回自定义DTO 方案一&#xff1a;返回Map 这个就不说了 方案二&#xff1a;实体定义成接口的形式 该方式最直观&#xff01;&#xff01;推荐&#xff01;&#xff01;&#xff01; 注意&#xff1a;XxxDto是interface接口&#xff0c;而…

前瞻断言与后瞻断言:JavaScript 正则表达式的秘密武器

JavaScript 中的前瞻断言&#xff08;lookahead&#xff09;和后瞻断言&#xff08;lookbehind&#xff09;相信用过的小伙伴就知道它的威力了&#xff0c;在一些特定的需求场景下&#xff0c;可以做到四两拨千斤的作用&#xff0c;今天让我们来盘点一下在 JavaScript 正则表达…

缓存和数据库双写的四种策略分析

概述 缓存是提升系统性能的极为简便的手段之一。相较而言&#xff0c;数据库&#xff08;或者 NoSQL 数据库&#xff09;的运行速度较为迟缓&#xff0c;然而速度在很多时候却是决胜的关键要素。采用缓存能够降低响应时间、减轻数据库负载并且节约成本。 正因如此&#xff0c;往…

银河麒麟搭建ftp服务器

1.先 查看系统架构&#xff0c;一般银河麒麟都是arrch64的 lscpu uname -a cat /etc/os-release 去下载对应版本的vsftp.rpm包和ftp包 Index of /NS/ (cs2c.com.cn) 1.安装rpm rpm -ivh *.rpm --nodeps --force #强制安装 2.修改配置文件 vi /etc/vsftpd/vsftpd.conf anon…

卡片式组件封装demo

效果视频&#xff1a; 卡片组件 样式还得细调~&#xff0c;时间有限&#xff0c;主要记录一下逻辑。 html结构&#xff1a; 目录 父组件数据处理数据格式 父组件的全部代码 子组件数据处理props参数 样式部分三个圆点点击三圆点在对应位置显示查看弹框点击非内容部分隐藏查看…

《系统架构设计师教程(第2版)》第12章-信息系统架构设计理论与实践-03-信息系统架构设计方法-ADM架构开发方法

文章目录 1. TOGAF概述1.1 概念1.2 目标1.3 包括的组件1.4 特色 2. ADM 架构开发方法2.1 ADM 的架构开发阶段2.2 各阶段的活动2.3 ADM方法的详细说明2.3.1 准备阶段2.3.2 阶段A——架构愿景2.3.3 阶段 B——业务架构2.3.4 阶段C——信息系统架构3.2.5 阶段 D——技术架构3.2.6 …

STM32智能家居系统教程

目录 引言环境准备智能家居系统基础代码实现&#xff1a;实现智能家居系统 4.1 数据采集模块 4.2 数据处理与控制模块 4.3 通信与网络系统实现 4.4 用户界面与数据可视化应用场景&#xff1a;家居智能化管理问题解决方案与优化收尾与总结 1. 引言 智能家居系统通过STM32嵌入…

R语言优雅的把数据基线表(表一)导出到word

基线表&#xff08;Baseline Table&#xff09;是医学研究中常用的一种数据表格&#xff0c;用于在研究开始时呈现参与者的初始特征和状态。这些特征通常包括人口统计学数据、健康状况和疾病史、临床指标、实验室检测、生活方式、社会经济等。 本人在既往文章《scitb包1.6版本发…

Go语言中的并发

简单介绍go中的并发编程. 涉及内容主要为goroutine, goroutine间的通信(主要是channel), 并发控制(等待、退出). 想查看更多与Go相关的内容, 可以查看我的Go编程栏目 Goroutine 语法 在一个函数调用前加上go即可, go func(). 语法很简单, 可以说是并发写起来最简单的程序语言…

数据结构(Java):力扣 二叉树面试OJ题(二)【进阶】

目录 &#x1f48e; 1、题一&#xff1a;二叉树的层序遍历 &#x1f31f; 1.1 思路1&#xff08;递归求解&#xff09; &#x1f31f; 1.1.1 思路1代码 &#x1f506; 1.2 思路2&#xff08;队列求解&#xff09; &#x1f506; 1.2.1 思路2代码 &#x1f48e; 2、题二&…

2024.7.16日 最新版 docker cuda container tookit下载!

nvidia官方指导 https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html 其实就是这几个命令&#xff0c;但是有墙&#xff1a; curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/shar…

【JavaEE】-- 网络编程基础概念(详解)

&#x1f387;&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了 博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳&#xff0c;欢迎大佬指点&#xff01; 人生格言: 当你的才华撑不起你的野心的时候,你就应该静下心来学习! 欢迎志同道合的朋友…

AV1技术学习: Compound Prediction

一、双向 Compound Prediction AV1支持两个参考帧的预测通过多种复合模式线性组合。复合预测公式为 其中&#xff0c;权重m(x, y) is scaled by 64 以进行整数计算&#xff0c;R1(x, y)和R2(x, y)表示两个参考块中位于(x, y)的像素。P(x, y)将按比例缩小 1/64 以形成最终的预测…

十五、【机器学习】【监督学习】- 神经网络回归

系列文章目录 第一章 【机器学习】初识机器学习 第二章 【机器学习】【监督学习】- 逻辑回归算法 (Logistic Regression) 第三章 【机器学习】【监督学习】- 支持向量机 (SVM) 第四章【机器学习】【监督学习】- K-近邻算法 (K-NN) 第五章【机器学习】【监督学习】- 决策树…

MyPostMan 迭代文档管理、自动化接口闭环测试工具(自动化测试篇)

MyPostMan 是一款类似 PostMan 的接口请求软件&#xff0c;按照 项目&#xff08;微服务&#xff09;、目录来管理我们的接口&#xff0c;基于迭代来管理我们的接口文档&#xff0c;文档可以导出和通过 url 实时分享&#xff0c;按照迭代编写自动化测试用例&#xff0c;在不同环…

定制QCustomPlot 带有ListView的QCustomPlot 全网唯一份

定制QCustomPlot 带有ListView的QCustomPlot 文章目录 定制QCustomPlot 带有ListView的QCustomPlot摘要需求描述实现关键字: Qt、 QCustomPlot、 魔改、 定制、 控件 摘要 先上效果,是你想要的,再看下面的分解,顺便点赞搜藏一下;不是直接右上角。 QCustomPlot是一款…

Spring中IoC容器和Bean

目录 IoC(Inversion of Control)控制反转思想 Spring技术对IoC思想的实现 DI(Dependency Injection)依赖注入 目标 最终效果 IoC入门案例 传统方法&#xff0c;不使用IoC思想调用dao层 使用IoC思想调用dao层 第一步&#xff1a;导入Spring坐标 第二步&#xff1a;创建…

stm32:CAN通讯

目录 介绍 协议层 CAN的 帧/报文 种类 数据帧 远程帧&#xff08;遥控帧&#xff09; 错误帧 过载帧 帧间隔 总线仲裁 stm32的CAN外设 工作模式 测试模式 功能框图 时序 标准时序 例子 环回静默模式测试 寄存器代码 HAL版本 介绍 一种功能丰富的车用总线标…