Java-Deque和Queue的使用、辨析和实战案例

news2024/12/23 20:05:23

0.前言

        在数据结构与算法中,队列是被经常使用的一种数据结构,总体上构成较为简单,但是Java在实际使用时易用错,经常会。比如 poll() 方法,add() 方法,offer() 方法,addFirst()方法,removeFirst()方法,removeLast() 方法,它们之间的对应关系是怎么样的,Queue和Deque使用和功能有何不同?本文主要探究这些问题。

1.队列这种数据结构

        作为一种经典的数据结构,栈承担了先进后出的责任,而在先进先出这方面,则由队列来完成。队列有单向队列,即最经典的队列,一头进,另一头出,而双端队列,两端都可以进出,比较灵活,所以造成了双端队列的api较多,在实际使用中经常会搞错方向。

        还有就是队列的头尾问题,分不清很容易在双端队列的removeFirst()方法或者是removeLast()方法中混淆。队列中的元素从哪边出去就是队列头,双端队列中两边都可以出去,但是沿着元素进入的方向能走出队列的一端为头。

        需要注意的是,队列是操作受限的线性表,所以,不是任何对线性表的操作都可以作为队列的操作。比如,不可以随便读取队列中间的某个数据。【3】

        关于队列的结构还可参考这篇文章,有助于理解:

        栈和队列相互实现 (用队列实现栈/用栈实现队列) 超详细~

2.Java Queue

        在Java中,Queue是队列的接口,主要的方法有6个,比较简单。常用的实现类有两个:LinkedList<>()和ArrayDeque<>()。

        官方文档:

1.add() 方法

添加元素到队尾

2.element()方法

查看队首元素

3.offer()方法

添加元素到队尾,和add()作用相同。队列有大小限制,在一个满的队列中加入一个新项,调用 add() 方法就会抛出一个 unchecked 异常,而调用 offer() 方法会返回 false,因此就可以在程序中进行有效的判断。【1】

4.peek()方法

查看队首元素,和peek()相同。队列为空, element()方法会抛出一个异常,peek() 返回 null。

5.poll()方法

删除队首元素

6.remove()方法

删除队首元素,和poll()方法相同。如果队列元素为空,调用remove()会出现异常,而 poll() 方法返回null。

7.其他方法

其他还有isEmpty()方法查看是否为空,size()方法查看队列长度等。

8.案例解析

可参考【3】

3.Java Deque

        双端队列的接口是Deque,和Queue一样,常见的实现的类都是LinkedList<>()和ArrayDeque<>(),因为两边都可以插入、删除元素,所以方法比较多。

1.插入元素

add() 添加元素到队尾,空间不足报异常,成功返回true。

addFirst() 添加元素到队头,空间不足报异常。

offerFirst() 添加元素到队头,成功返回true,否则返回false。

addLast() 添加元素到队尾,空间不足报异常。

offerLast() 添加元素到队尾,成功返回true,否则返回false。

push() 添加元素到队头,此处承担栈的作用,等价于addFirst(),空间不足报异常。

2.删除元素

remove() 删除头元素

removeFirst() 删除头元素,为空报异常。

removeLast() 删除尾元素,为空报异常。

pollFirst() 删除头元素,为空返回null。

pollLast() 删除尾元素,为空返回null。

pop() 删除头元素,此处承担栈的作用,等价于removeFirst(),为空报异常。

3.查看元素

getFirst() 查看头元素,为空报异常。
getLast() 查看尾元素,为空报异常。
peekFirst() 查看头元素,为空返回null。
peekLast() 查看尾元素,为空返回null。

4.案例演示

可参考【2】

4.辨析

        在整体上,Queue可以看作是Deque的子集,Queue有的功能Deque都有,因为是双端队列,两边都可以插入和删除,所以Deque要比Queue更灵活,在有些题目中,会出现必须要双端队列的情况,因为两边都需要删除,而Queue做不到这一点。

        还有,在一些题目中,会要求只能用队列,不能使用双端队列,需要注意。另外,由于双端队列可以先进后出,也可以当作栈来使用,例如经典的问题,使用队列实现栈,可以用一个双端队列实现,也可以用两个队列实现。

        等效方法【1】:

5.leetcodde案例

1. leetcode225 用队列实现栈 

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。
实现 MyStack 类:
void push(int x) 将元素 x 压入栈顶。
int pop() 移除并返回栈顶元素。
int top() 返回栈顶元素。
boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。

注意:

你只能使用队列的基本操作 —— 也就是 push to back、peek/pop from front、size 和 is empty 这些操作。你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
 

class MyStack {
    Deque<Integer> list1;
    Deque<Integer> list2;
    public MyStack() {
        list1 = new ArrayDeque<>();
        list2 = new ArrayDeque<>();
    }
    
    public void push(int x) {
        list2.add(x);
        while(!list1.isEmpty()){
            list2.add(list1.remove());//add poll
        }
        Deque<Integer> temp = list1;
        list1 = list2;
        list2 = temp;
    }
    
    public int pop() {
        return list1.remove();
    }
    
    public int top() {
        return list1.peek();
    }
    
    public boolean empty() {
        return list1.isEmpty();
    }
}

本题小结

(1)一个主队列,一个辅助队列,主队列时刻保持最新状态

(2)主队列保持最新就意味着(top/Empty/pop)等操作都对最新的队列即主队列操作

(3)来一个新的元素放到辅助队列,然后把主队列的元素都丢到辅助队列,交换即最新

 以题中的案例为例,画出主辅队列的变化:

输入:
["MyStack", "push", "push", "top", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 2, 2, false]

解释:
MyStack myStack = new MyStack();
myStack.push(1);
myStack.push(2);
myStack.top(); // 返回 2
myStack.pop(); // 返回 2
myStack.empty(); // 返回 False

 

此题目也可以使用一个双端队列来实现

可见另一篇文章:

栈和队列相互实现 (用队列实现栈/用栈实现队列) 超详细~

2. leetcode232 用栈实现队列

可见这篇文章,比较详细  栈和队列相互实现 (用队列实现栈/用栈实现队列) 超详细~

3. leetcode102 二叉树的层序遍历

给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:[[3],[9,20],[15,7]]

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> list = new ArrayList<>();
        Deque<TreeNode> queue = new LinkedList<>();
        if(root == null) return list;
        queue.addLast(root);
        while(!queue.isEmpty()){
            int len = queue.size();
            List<Integer> temp = new ArrayList<>();
            for(int i = 0; i < len; i++){
                TreeNode cur = queue.pollFirst();
                temp.add(cur.val);
                if(cur.left != null){
                    queue.addLast(cur.left);
                }
                if(cur.right != null){
                    queue.addLast(cur.right);
                }
            }
            list.add(temp);
        } 
        return list;
    }
}

 详细解析:

Java-数据结构-二叉树<三>

4.leetcode  面试题59 - II. 队列的最大值 

请定义一个队列并实现函数 max_value 得到队列里的最大值,要求函数max_value、push_back 和 pop_front 的均摊时间复杂度都是O(1)。

若队列为空,pop_front 和 max_value 需要返回 -1

输入: 
["MaxQueue","push_back","push_back","max_value","pop_front","max_value"]
[[],[1],[2],[],[],[]]
输出: [null,null,null,2,1,2]
class MaxQueue {
    Deque<Integer> deque1;
    Deque<Integer> deque2;

    public MaxQueue() {
        deque1 = new LinkedList<>();
        deque2 = new LinkedList<>();
    }
    
    public int max_value() {
        if(deque2.isEmpty()) return -1;
        return deque2.peekFirst();
    }
    
    public void push_back(int value) {
        deque1.addLast(value);
        while(!deque2.isEmpty() && value > deque2.peekLast()){
            deque2.removeLast();
        }
        deque2.addLast(value);
    }
    
    public int pop_front() {
        if(deque1.isEmpty()){
            return -1;
        }
        if(deque1.peekFirst().equals(deque2.peekFirst())){
            deque2.removeFirst();
            return deque1.removeFirst();
        }
        return deque1.removeFirst();
    }
}

本题小结

(1)一个主队列,一个辅助队列,主队列存所有的元素,而辅助队列只存最大值

(2)一个新的队列元素来到之后,放到主队列,而在辅助队列中,要依次比较新值和辅助队列中的值

(3)在去除元素时,要注意辅助队列和主队列元素是否一致,主队列的元素一直比辅助队列多,因为辅助队列只保存最大值

6.参考来源

【1】CSDN Jason&Zhou Java数据结构之Deque(双端队列)

【2】CSDN onedegree java关于Deque的使用

【3】CSDN  Sueko Java中队列(Queue)用法

【4】Leetcode Krahets(K神) 剑指 Offer 59 - II. 队列的最大值(单调双向队列,清晰图解)

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

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

相关文章

论文投稿指南——中文核心期刊推荐(石油、天然气工业 3)

【前言】 &#x1f680; 想发论文怎么办&#xff1f;手把手教你论文如何投稿&#xff01;那么&#xff0c;首先要搞懂投稿目标——论文期刊 &#x1f384; 在期刊论文的分布中&#xff0c;存在一种普遍现象&#xff1a;即对于某一特定的学科或专业来说&#xff0c;少数期刊所含…

uni-app ①

文章目录一、uni-app简介学习 uniapp 本质uniapp 优势uni-app 和 vue 的关系uni-app 和小程序有什么关系uniapp 与 web 代码编写区别课程内容学习重点知识点一、uni-app 简介 uni-app 是一个使用 Vue.js 进行 开发所有前端应用的框架。开发者编写一套代码&#xff0c;即可发布…

从数据备份保护到完整生命周期管理平台,爱数全新发布 AnyBackup Family 8

编辑 | 宋慧 出品 | CSDN 云计算 从2003年创业&#xff0c;开始做数据备份技术&#xff0c;爱数已经走过了近20年的时间。现在&#xff0c;数据的价值被越来越多的业界与用户看到&#xff0c;数据分析应用赛道近年一直持续火热。而现在的爱数在做的&#xff0c;已经从数据的备…

【Python实战】神仙运气—快看看你的彩票:2千多万元大奖无人领,马上就过期了,下一期的中奖者会是你吗?(纯技术交流)

前言 越努力越幸运 哈喽~我是栗子同学&#xff01; 特别注意&#xff1a;不管是沉迷赌球&#xff0c;还是沉迷购彩&#xff0c;都是不可取的。本文纯是一个技术学习内容。 听说关注我的人会暴富哦&#xff01;、 所有文章完整的素材源码都在&#x1f447;&#x1f447; 粉丝…

数据仓库原理 - 概念、架构、建模方法

目录1、介绍1.1 数据仓库诞生原因1.2 数据仓库概述1.3 数仓的技术实现1.4 MPP&分布式架构MPP架构分布式架构MPP分布式架构1.5 常见产品2、架构2.1 架构图ETLODSCDMADS2.2 ETL流程数据抽取数据转换数据加载ETL工具2.3 数据积存操作数据层ODS2.4 数据分析数据明细层DWD数据汇…

【scipy.sparse包】Python稀疏矩阵详解

【scipy.sparse包】Python稀疏矩阵 文章目录【scipy.sparse包】Python稀疏矩阵1. 前言2. 导入包3. 稀疏矩阵总览4. 稀疏矩阵详细介绍4.1 coo_matrix4.2 dok_matrix4.3 lil_matrix4.4 dia_matrix4.5 csc_matrix & csr_matrix4.6 bsr_matrix5. 稀疏矩阵的存取5.1 用save_npz保…

MATLAB 遗传算法

✅作者简介&#xff1a;人工智能专业本科在读&#xff0c;喜欢计算机与编程&#xff0c;写博客记录自己的学习历程。 &#x1f34e;个人主页&#xff1a;小嗷犬的个人主页 &#x1f34a;个人网站&#xff1a;小嗷犬的技术小站 &#x1f96d;个人信条&#xff1a;为天地立心&…

CSS布局之详解

在开发前端的时候&#xff0c;界面布局尤为重要&#xff0c;要布局的非常合理&#xff0c;好看&#xff0c;css是必不可少的&#xff0c;然后是各种布局&#xff0c;使用这些布局&#xff0c;进行混合搭配&#xff0c;最终的目的都是开发一个完整的界面。前端的技术变化是五花八…

mybatis-plus ---1

mybatis-plus 在mybatis的基础上只做加强&#xff0c;不做删减。 一个简单的mybatis-plus案例 结构图 创建一个springboot工程 添加依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0…

Linux(Linux各目录结构详解)

我们知道Linux系统是一个文件系统&#xff0c;它的文件系统就类似windows系统下的磁盘文件系统。 我们连接上一台linux系统的服务器。 输入命令 &#xff1a; ls / 我们可以看到 linux系统的根目录下有这些目录 bin boot data dev etc hbr home lib lib64 lostfoun…

【前端】参考C站动态发红包界面,高度还原布局和交互

最近有些小伙伴咨询博主说前端布局好难&#xff0c;其实都是熟能生巧&#xff01; 模仿C站动态发红包界面&#xff0c;cssdiv实现布局&#xff0c;纯javascript实现交互效果 目录 1、界面效果 2、界面分析 2.1、整体结构 2.2、标题 2.3、表单 2.4、按钮 3、代码实现 3.…

【目标检测】如何使用Yolov8

如何使用Yolov8一、前言二、用法2.1 安装2.2 使用方法2.3 模型2.3.1 目标检测2.3.2 实例分割2.3.3 分类一、前言 一种易于使用的新的对象检测模型。 由 Ultralytics 开发的 Ultralytics YOLOv8 是一种尖端的、最先进的 (SOTA) 模型&#xff1a; https://github.com/ultralyt…

前端调试2

一、用chrome调试(node.js)例&#xff1a;const fs require(fs/promises);(async function() {const fileContent await fs.readFile(./package.json, {encoding: utf-8});await fs.writeFile(./package2.json, fileContent); })();1.先 node index.js 跑一下&#xff1a;2.然…

并发包工具之 批量处理任务 CompletionService(异步)、CompletableFuture(回调)

文章目录一、处理异步任务并获取返回值——CompletionService二、线程池三、Callable 与 Future四、通过回调方式处理可组合编排任务——CompletableFuture一、处理异步任务并获取返回值——CompletionService 特点描述&#xff1a; 对于比较复杂的计算&#xff0c;把…

dfs(九)字符串的全排列

字符串的排列_牛客题霸_牛客网【牛客题霸】收集各企业高频校招笔面试题目&#xff0c;配有官方题解&#xff0c;在线进行百度阿里腾讯网易等互联网名企笔试面试模拟考试练习,和牛人一起讨论经典试题,全面提升你的技术能力https://www.nowcoder.com/practice/fe6b651b66ae47d7ac…

Windows 安装Tomcat

版本:tomcat8.5jdk-8u231一.解压JDK安装包 更换JDK安装路径二.解压安装Tomcat 选择jdk安装路径更换tomcat安装路径三.设置环境变量 1.“环境变量”界面中系统变量点击”新建“&#xff0c;创建CATALINA_HOMEC:\RESSET\tomcat&#xff08;Tomcat服务器的根目录&#xff09;2.创建…

电脑录屏win+g没反应怎么办?打开这2个开关,就能解决

有不少的小伙伴在使用电脑自带的录屏软件的时候&#xff0c;发现录屏快捷键wing没反应了。电脑录屏wing没反应怎么办&#xff1f;解决办法很简单&#xff0c;只需要打开2个开关&#xff0c;就能够快速解决&#xff0c;一起来看看吧&#xff01; 一、电脑录屏wing没反应怎么办&a…

响应式布局之viewport-超级简单

之前文章CSS布局之详解_故里2130的博客-CSDN博客 上面的文章可以实现响应式布局&#xff0c;根据浏览器的大小变化而变化&#xff0c;但是相对于viewport来说&#xff0c;之前的还是有点复杂&#xff0c;而使用viewport更加的简单。 当我们使用amfe-flexible的时候&#xff0…

记录ideal中使用springboot遇到的问题

持续记录&#xff0c;避免反复查找资料 选择Maven构建项目 创建springboot项目时&#xff0c;【Project Metadata页】的Type选项默认是Gradle&#xff0c;如果要使用Maven需要修改选项&#xff0c;如下图 mysql依赖包直接在pom.xml中添加 创建时在对话框中勾选【Mysql Driver】…

两个月,测试转岗产品经理,我是怎么规划的?

​本期同学依旧来自深圳 测试到产品转变&#xff0c;用了两个月 本周&#xff0c;为大家介绍M同学的佛系转岗经历 学员档 学员档案 原岗位&#xff1a;测试 转岗级别&#xff1a;中级产品经理 转岗特点&#xff1a; 1.未接触产品工作 2.对岗位地点要求严格 先看结果 …