Java栈和队列·下
Java栈和队列·下
- 2. 队列(Queue)
- 2.1 概念
- 2.2 实现
- 2.3 相似方法的区别
- 2.4 循环队列
- 3. 双端队列 (Deque)
- 3.1 概念
- 4.java中的栈和队列
- 5. 栈和队列面试题
大家好,我是晓星航。今天为大家带来的是 Java栈和队列·下 的讲解!😀
继上一个讲完的栈后,我们这次开始讲解队列!
2. 队列(Queue)
2.1 概念
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾(Tail/Rear) 出队列:进行删除操作的一端称为队头(Head/Front)

在idea中看Queue(队列的底层逻辑代码)时 按下 alt + 7 可以查看它包含的所有方法:

2.2 实现
队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。





class Node {public int val;public Node next;public Node(int val) {this.val = val;}}
public class MyQueue {public Node head;public Node last;/*** 尾插法* @param val*/public void offer(int val) {Node node = new Node(val);if (head == null) {head = node;last = node;} else {last.next = node;last = last.next;}}public int poll() {if (isEmpty()) {throw new RuntimeException("队列为空");}int oldVal = head.val;head = head.next;return oldVal;}public boolean isEmpty() {return this.head == null;}public int peek() {if (isEmpty()) {throw new RuntimeException("队列为空");}return head.val;}}
下面为测试代码:
public class TestDemo {public static void main(String[] args) {MyQueue queue = new MyQueue();queue.offer(1);queue.offer(2);queue.offer(3);System.out.println(queue.peek());System.out.println(queue.poll());System.out.println(queue.poll());System.out.println(queue.poll());System.out.println(queue.poll());}

Queue中方法总结:
add 增加一个元索 如果队列已满,则抛出一个IIIegaISlabEepeplian异常
remove 移除并返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常
element 返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常
offer 添加一个元素并返回true 如果队列已满,则返回false
poll 移除并返问队列头部的元素 如果队列为空,则返回null
peek 返回队列头部的元素 如果队列为空,则返回null
put 添加一个元素 如果队列满,则阻塞
take 移除并返回队列头部的元素
2.3 相似方法的区别
1、add()和offer()区别:
add()和offer()都是向队列中添加一个元素。一些队列有大小限制,因此如果想在一个满的队列中加入一个新项,调用 add() 方法就会抛出一个 unchecked 异常,而调用 offer() 方法会返回 false。因此就可以在程序中进行有效的判断!
2、poll()和remove()区别:
remove() 和 poll() 方法都是从队列中删除第一个元素。如果队列元素为空,调用remove() 的行为与 Collection 接口的版本相似会抛出异常,但是新的 **poll() 方法在用空集合调用时只是返回 null。**因此新的方法更适合容易出现异常条件的情况。
3、element() 和 peek() 区别:
element() 和 peek() 用于在队列的头部查询元素。与 remove() 方法类似,在队列为空时, element() 抛出一个异常,而 peek() 返回 null。
2.4 循环队列
实际中我们有时还会使用一种队列叫循环队列。如操作系统课程讲解生产者消费者模型时可以就会使用循环队列。环形队列通常使用数组实现。

数组下标循环的小技巧
-
- 下标最后再往后(offset 小于 array.length): index = (index + offset) % array.length

- 下标最前再往前(offset 小于 array.length): index = (index + array.length - offset) % array.length

如何区分空与满

- 通过添加 size 属性记录 使用size和数组长度比较,确定满或者空

-
使用标志位flag,最开始falg = false,
入队列时,每放一个元素,falg就置为true
出队列时,每出一个元素,falg就置为false
当front和rear相遇时,falg为true则队列为满,falg为false则队列为空。

- 浪费一个格子来区分空和满,每次存放元素之前,都先检查一下rear的下一个是不是front。如果是,那么就是满的
空:frontNext == rear
满:rearNext == front


3. 双端队列 (Deque)
3.1 概念
双端队列(deque)是指允许两端都可以进行入队和出队操作的队列,deque 是 “double ended queue” 的简称。那就说明元素可以从队头出队和入队,也可以从队尾出队和入队。
双端队列的所有方法:

4.java中的栈和队列


栈的方法:

普通队列方法:

双端队列方法:


5. 栈和队列面试题
- 括号匹配问题。OJ链接

import java.util.Stack;
class Solution {public boolean isValid(String s) {Stack<Character> stack = new Stack<>();for (int i = 0; i < s.length(); i++) {char ch = s.charAt(i);if (ch == '(' || ch == '[' || ch == '{' ) {//如果是左括号直接入栈stack.push(ch);} else {//如果是右括号if (stack.empty()) {//右括号多System.out.println("右括号多!");return false;}char top = stack.peek();if (top == '(' && ch == ')' || top == '[' && ch == ']' || top == '{' && ch == '}') {//如果左括号和右括号匹配 则弹出这个左括号stack.pop();} else {//左右括号不匹配System.out.println("左右括号不匹配");return false;}}}if (!stack.empty()) {//左括号多System.out.println("左括号多!");return false;}return true;}
}
题目描述的很清楚,左右括号如果不匹配,无非是以下几种情况:
1、左括号多余右括号
2、右括号多余左括号
3、左右括号顺序不想匹配
在使用代码将这几种情况考虑完全后,便可轻易通过测试。
思路如下:
如果是左括号我们直接使其进栈,如果是右括号我们先判断右括号是否比左括号多,再看其是否相匹配,匹配则弹出相对应的左括号继续下一个括号的判断,如果不匹配则返回不匹配错误,在右括号全部判断完毕后,我们判断一下栈此时是否为空,如果为空则我们所有的括号都匹配成功即正确,如果不为空则是左括号比右括号要多,我们就返回false。

- 用队列实现栈。OJ链接


public class MyStack {private Queue<Integer> qu1;private Queue<Integer> qu2;public MyStack() {qu1 = new LinkedList<>();qu2 = new LinkedList<>();}public void push(int x) {if (!qu1.isEmpty()) {qu1.offer(x);} else if (!qu2.isEmpty()){qu2.offer(x);} else {qu1.offer(x);}}public int pop() {if (empty()) {return -1;}if (!qu1.isEmpty()) {int size = qu1.size();for (int i = 0; i < size - 1; i++) {int val = qu1.poll();qu2.offer(val);}return qu1.poll();}if (!qu2.isEmpty()) {int size = qu2.size();for (int i = 0; i < size - 1; i++) {int val = qu2.poll();qu1.offer(val);}return qu2.poll();}return -1;}public int top() {if (empty()) {return -1;}if (!qu1.isEmpty()) {int val = -1;int size = qu1.size();for (int i = 0; i < size; i++) {val = qu1.poll();qu2.offer(val);}return val;}if (!qu2.isEmpty()) {int val = -1;int size = qu2.size();for (int i = 0; i < size; i++) {val = qu2.poll();qu1.offer(val);}return val;}return -1;}public boolean empty() {return qu1.isEmpty() && qu2.isEmpty();}
}
1、入栈的时候,入到不为空的队列,刚开始都为空指定入到一个队列。
2、出栈的时候,找到不为空的队列,出size-1个元素到另一个队列,剩下这个元素就是出栈的元素。
注意:这里有一个小问题我们很容易疏忽,就是在使用top和pop方法进行移动时我们qu1和qu2中的元素个数时变化的,因此我们的qu1.size() qu2.size()也会跟着变化,为了避免这个情况,我们在for循环的外面自己定义一个Int size = qu1.size(); int size = qu2.size();在之后的for循环中我们只需要让i小于size即可,此时的size就不是一个会变动的值了。

- 用栈实现队列。OJ链接


class MyQueue {public Stack<Integer> stack1;public Stack<Integer> stack2;public MyQueue() {stack1 = new Stack<>();stack2 = new Stack<>();}public void push(int x) {stack1.push(x);}public int pop() {if (empty()) {return -1;}if (stack2.empty()) {while (!stack1.isEmpty()) {stack2.push(stack1.pop());}}return stack2.pop();}public int peek() {if (empty()) {return -1;}if (stack2.empty()) {while (!stack1.isEmpty()) {stack2.push(stack1.pop());}}return stack2.peek();}public boolean empty() {return stack1.isEmpty() && stack2.isEmpty();}
}
思路:1、入队的时候,统一入到第1个栈
2、出队的时候,同一出第2个栈里面的元素,如果第2个为空,那么把第一个栈里面所有的元素,全部倒过来,然后再出栈顶的元素。

- 实现一个最小栈。OJ链接


class MinStack {private Stack<Integer> stack;private Stack<Integer> minStack;public MinStack() {stack = new Stack<>();minStack = new Stack<>();}public void push(int val) {stack.push(val);if (!minStack.empty()) {int top = minStack.peek();//比较 小于等于的话 也要放进来if (val <= top) {minStack.push(val);}} else {minStack.push(val);}}public void pop() {int popVal = stack.pop();if (!minStack.empty()) {int top = minStack.peek();if (top == popVal) {minStack.pop();}}}public int top() {return stack.peek();}public int getMin() {return minStack.peek();}
}
思路:这里我们采取了使用两个栈(一个普通栈 一个最小栈)来比较的方法,例如我们在push元素时,普通栈我们是直接放进去的,而最小栈我们则是通过比较,如果要放的元素比我们最小栈栈顶的元素小或等于我们便在最小栈也放入一份。
在pop弹出栈顶元素时我们同样是直接弹出普通栈的栈顶元素,然后比较这个弹出的元素和最小栈栈顶元素的大小是否相等,如果相等我们则还需要再pop一次最小栈的栈顶元素。
top方法和我们stack栈中的peek方法一样,我们直接返回stack的peek方法即可。
getMin方法是返回栈中最小元素,我们这里有两个栈,而最小栈的原理就是将最小的元素通过压栈(头插)的方式进入最小栈,因此我们最小栈的最小值永远是栈顶的元素,我们直接返回最小栈的栈顶元素即可。

- 设计循环队列。OJ链接


class MyCircularQueue {public int[] elem;public int front;//队头下标public int rear;//队尾下标public MyCircularQueue(int k) {this.elem = new int[k + 1];}/*** 入队操作* @param value* @return*/public boolean enQueue(int value) {if (isFull()) {return false;}this.elem[rear] = value;//rear++;rear = (rear + 1) % elem.length;return true;}/*** 出队操作* @return*/public boolean deQueue() {if (isEmpty()) {return false;}front = (front + 1) % elem.length;return true;}/*** 得到队头元素* @return*/public int Front() {if (isEmpty()) {return -1;}return elem[front];}public int Rear() {if (isEmpty()) {return -1;}int index = -1;if (rear == 0) {index = elem.length - 1;} else {index = rear - 1;}return elem[index];}public boolean isEmpty() {return front == rear;}public boolean isFull() {//rear的下一个是frontif ((this.rear + 1) % elem.length == front) {return true;}return false;}
}
解答思路:我们这里的数组元素为k个,但是所能用的位置只有k-1个,为了满足题目要求我们将数组大小改为了k+1,故我们所能用的元素变为了k个。这里因为我们是循环队列,因此当数组为空时,或者数组占满时我们的front和rear是相等的,为了避免数组占满,而要计算rear要循环回我们的首元素地址0时,我们采取了rear = (rear + 1) % elem.length的操作,如果rear的下标已经时数组下标的最大值,再加1就会自动归为首元素的下标0。


感谢各位读者的阅读,本文章有任何错误都可以在评论区发表你们的意见,我会对文章进行改正的。如果本文章对你有帮助请动一动你们敏捷的小手点一点赞,你的每一次鼓励都是作者创作的动力哦!😘
相关文章:

Java栈和队列·下
Java栈和队列下2. 队列(Queue)2.1 概念2.2 实现2.3 相似方法的区别2.4 循环队列3. 双端队列 (Deque)3.1 概念4.java中的栈和队列5. 栈和队列面试题大家好,我是晓星航。今天为大家带来的是 Java栈和队列下 的讲解!😀 继上一个讲完的栈后&…...

b01lers CTF web 复现
warmup 按照提示依次 base64 加密后访问,可以访问 ./flag.txt,也就是 Li9mbGFnLnR4dA 。 from base64 import b64decode import flaskapp flask.Flask(__name__)app.route(/<name>) def index2(name):name b64decode(name)if (validate(name))…...

三月份跳槽了,历经字节测开岗4轮面试,不出意外,被刷了...
大多数情况下,测试员的个人技能成长速度,远远大于公司规模或业务的成长速度。所以,跳槽成为了这个行业里最常见的一个词汇。 前几天,我看到有朋友留言说,他在面试字节的测试开发工程师的时候,灵魂拷问三小…...

springboot+vue驾校管理系统 idea科目一四预约考试,练车
加大了对从事道路运输经营活动驾驶员的培训管理力度,但在实际的管理过程中,仍然存在以下问题:(1)管理部门内部人员在实际管理过程中存在人情管理,不进行培训、考试直接进行发证。(2)从业驾驶员培训机构不能严格执行管理部门的大纲…...

【pytorch】使用deepsort算法进行目标跟踪,原理+pytorch实现
目录deepsort流程一、匈牙利算法二、卡尔曼滤波车速预测例子动态模型的概念卡尔曼滤波在deepsort中的动态模型三、预测值及测量值的含义deepsort在pytorch中的运行deepsort流程 DeepSORT是一种常用的目标跟踪算法,它结合了深度学习和传统的目标跟踪方法。DeepSORT的…...

Python 基础教程【3】:字符串、列表、元组
本文已收录于专栏🌻《Python 基础》文章目录🌕1、字符串🥝1.1 字符串基本操作🍊1.1.1 字符串创建🍊1.1.2 字符串元素读取🍊1.1.3 字符串分片🍊1.1.4 连接和重复🍊1.1.5 关系运算&…...

(数据结构)八大排序算法
目录一、常见排序算法二、实现1. 直接插入排序2.🌟希尔排序3. 选择排序4.🌟堆排序5. 冒泡排序7. 🌟快速排序7.1 其他版本的快排7.2 优化7.3 ⭐非递归7. 🌟归并排序7.1 ⭐非递归8. 计数排序三、总结1. 分析排序 (Sorting) 是计算机…...

构建GRE隧道打通不同云商的云主机内网
文章目录1. 环境介绍2 GRE隧道搭建2.1 华为云 GRE 隧道安装2.2 阿里云 GRE 隧道安装3. 设置安全组4. 验证GRE隧道4.1 在华为云上 ping 阿里云云主机内网IP4.2 在阿里云上 ping 华为云云主机内网IP5. 总结1. 环境介绍 华为云上有三台云主机,内网 CIDR 是 192.168.0.0…...

48天C++笔试强训 001
作者:小萌新 专栏:笔试强训 作者简介:大二学生 希望能和大家一起进步! 本篇博客简介:讲解48天笔试强训第一天的题目 笔试强训 day1选择题12345678910编程题12选择题 1 以下for循环的执行次数是(ÿ…...

Android 11新增系统服务
1.编写.aidl文件存放位置:frameworks/base/core/java/android/ospackage android.os;interface ISystemVoiceServer {void setHeightVoice(int flag);void setBassVoice(int flag);void setReverbVoice(int flag);}2.将.aidl文件添加到frameworks/base/Android.bp f…...
“你要多弄弄算法”
开始瞎掰 ▽ 2月的第一天,猎头Luna给我推荐了字节的机会,菜鸡我呀,还是有自知之明的,赶忙婉拒:能力有限,抱歉抱歉。 根据我为数不多的和猎头交流的经验,一般猎头都会稍微客套一下:…...

【数据结构】千字深入浅出讲解队列(附原码 | 超详解)
🚀write in front🚀 📝个人主页:认真写博客的夏目浅石. 🎁欢迎各位→点赞👍 收藏⭐️ 留言📝 📣系列专栏:C语言实现数据结构 💬总结:希望你看完…...
vue面试题(day04)
vue面试题vue插槽?vue3中如何获取refs,dom对象的方式?vue3中生命周期的和vue2中的区别?说说vue中的diff算法?说说 Vue 中 CSS scoped 的原理?vue3中怎么设置全局变量?Vue中给对象添加新属性时&a…...

自动标注工具 Autolabelimg
原理简介~~ 对于数据量较大的数据集,先对其中一部分图片打标签,Autolabelimg利用已标注好的图片进行训练,并利用训练得到的权重对其余数据进行自动标注,然后保存为xml文件。 一、下载yolov5v6.1 https://github.com/ultralytic…...
2023-03-20干活
transformer复现 from torch.utils.data import Dataset,DataLoader import numpy as np import torch import torch.nn as nn import os import time import math from tqdm import tqdmdef get_data(path,numNone):all_text []all_label []with open(path,"r",e…...
Java 注解(详细学习笔记)
注解 注解英文为Annotation Annotation是JDK5引入的新的技术 Annotation的作用: 不是程序本身,可以对程序做出解释可以被其他程序(比如编译器)读取。 Annotation的格式: 注解是以注解名在代码中存在的,还…...

LeetCode:35. 搜索插入位置
🍎道阻且长,行则将至。🍓 🌻算法,不如说它是一种思考方式🍀算法专栏: 👉🏻123 一、🌱35. 搜索插入位置 题目描述:给定一个排序数组和一个目标值&…...
菜鸟刷题Day2
菜鸟刷题Day2 一.判定是否为字符重排:字符重排 描述 给定两个由小写字母组成的字符串 s1 和 s2,请编写一个程序,确定其中一个字符串的字符重新排列后,能否变成另一个字符串。 解题思路: 这题思路与昨天最后两道类似&…...

Selenium基础篇之不打开浏览器运行
文章目录前言一、场景二、设计1.引入库2.引入浏览器配置3.设置无头模式4.启动浏览器实例,添加配置信息5.访问质量分地址6.隐式等待5秒7.定位到输入框8.输入博文地址9.定位到查询按钮10.点击查询按钮11.定位到查询结果模块div12.打印结果13.结束webdriver进程三、结果…...

【数据结构初阶】栈与队列笔试题
前言在我们学习了栈和队列之后,今天来通过几道练习题来巩固一下我们的知识。题目一 用栈实现队列题目链接:232. 用栈实现队列 - 力扣(Leetcode)这道题难度不是很大,重要的是我们对结构认识的考察,由于这篇文…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...

苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...

Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...
【HTML-16】深入理解HTML中的块元素与行内元素
HTML元素根据其显示特性可以分为两大类:块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...

Python Ovito统计金刚石结构数量
大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...

【C++进阶篇】智能指针
C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...

android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...

Ubuntu Cursor升级成v1.0
0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开,快捷键也不好用,当看到 Cursor 升级后,还是蛮高兴的 1. 下载 Cursor 下载地址:https://www.cursor.com/cn/downloads 点击下载 Linux (x64) ,…...
Docker拉取MySQL后数据库连接失败的解决方案
在使用Docker部署MySQL时,拉取并启动容器后,有时可能会遇到数据库连接失败的问题。这种问题可能由多种原因导致,包括配置错误、网络设置问题、权限问题等。本文将分析可能的原因,并提供解决方案。 一、确认MySQL容器的运行状态 …...