Collection与数据结构 Stack与Queue(二):队列与Queue

1. 队列

1.1 概念

只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾(Tail/Rear) 出队列:进行删除操作的一端称为队头(Head/Front).
在这里插入图片描述
这样的数据结构有些像我们平时在食堂排队打饭的操作.

1.2 队列的使用

在Java中,Queue是一个接口,底层是通过链表来实现的.所以在实例化的时候,必须用LinkedList来实例化.
在这里插入图片描述

方法功能
boolean offer(E e)入队列
E poll()出队列
peek()获取队头元素
int size()获取队列中有效元素个数
boolean isEmpty()检测队列是否为空
  • offer和poll操作的时间复杂度都是O(1),所以在使用单向链表实现队列的时候,必须使用头插尾插.如果说是尾删头插的话,删掉的时候不知道该结点的pre是谁(因为是单向链表),所以要重新遍历寻找最后一个结点,时间复杂度就不是O(1).
public static void main(String[] args) {Queue<Integer> q = new LinkedList<>();q.offer(1);q.offer(2);q.offer(3);q.offer(4);q.offer(5);                  // 从队尾入队列System.out.println(q.size());System.out.println(q.peek());  // 获取队头元素q.poll();System.out.println(q.poll());  // 从队头出队列,并将删除的元素返回if(q.isEmpty()){System.out.println("队列空");}else{System.out.println(q.size());}
}

1.3 队列的模拟实现

我们根据队列底层的逻辑:使用LinkedList来实现队列.

public class MyQueue {public static class ListNode{ListNode next;ListNode pre;int val;public ListNode(int val) {this.val = val;}}ListNode first;ListNode last;int size = 0;/*** 入队列,在双向链表的尾部插入新结点* @param e*/public void offer (int e){ListNode listNode = new ListNode(e);if (first == null){first = listNode;last = listNode;}else {listNode.pre = last;last.next = listNode;last = listNode;}size++;}/*** 出队列,在链表头部删除结点* @return*/public int poll(){int value = 0;if (first == null){return -1;} else if (first == last) {value = first.val;//需要先把value记录下来,以便最后返回first = null;last = null;//return value;//不可以直接返回first.val,否者空指针异常}else {value = first.val;first = first.next;first.pre.next = null;first.pre = null;//return value;}size --;//在返回之前size--return value;}/*** 返回队头元素* @return*/public int peek(){if (first == null){return -1;}return first.val;}/*** 获取队列大小* @return*/public int size(){return this.size;}/*** 判断队列是否为空* @return*/public boolean isEmpty(){return size == 0;}
}

1.4 环形队列

在实际中,我们经常用的一种队列还有一种,叫做循环队列,环形队列通常由数组实现.
在这里插入图片描述
既然是环形队列,所以我们在存放元素的时候,就要按循环下标的方式来添加元素,数组下标循环公式:
(当前位置+偏移量)%数组大小.
eg:在这里插入图片描述
区分空与满的问题:
在一个队列中,一定会有队头和队尾,在队列空的时候,队列头和尾指向同一位置:
在这里插入图片描述
在队列满的时候,头和尾也会指向同一位置:
在这里插入图片描述
如果按上述的方法,我们就没有办法区别队列是空还是满了,那么我们提供以下解决方案:

  • 通过添加size属性
  • 保留一个位置(牺牲空间法)
  • 使用标记

在下面,我们只以第二种方法为例:我们令头为front,尾为rear
在这里插入图片描述
在满的时候,我们通过把最后一个位置空出来,以front = (rear+1)%array.length来表示队列满.
下面我们来通过上述方式设计循环队列:

OJ链接

class MyCircularQueue {public int front;//队头public int rear;//队尾public int[] elem;public MyCircularQueue(int k) {front = 0;rear = 0;elem = new int[k+1];//使用牺牲空间法来区分满和空,初始化空间的时候就要多一个空间}public boolean enQueue(int value) {if(isFull()){return false;//队列为满,返回false}else{elem[rear] = value;rear = (rear+1)%elem.length;}return true;}public boolean deQueue() {if(front == rear){return false;//队列为空,删除失败}else{elem[front] = 0;front = (front+1)%elem.length;}return true;}public int Front() {if(rear == front){return -1;}else{return elem[front];}}public int Rear() {if(rear == front){return -1;}else{return rear == 0? elem[elem.length-1]:elem[rear-1];}//分两种情况,一种是rear为0,一种是不为0的时候,为0返回数组的最后一个元素,否者返回rear指向的前一个元素}//队尾放的最后一个元素总是比rear指针向前一个位置,因为在插入操作的时候,最后进行了rear = (rear+1)%elem.length操作public boolean isEmpty() {if(rear == front){return true;//头和尾重合的时候,就是空}else{return false;}}public boolean isFull() {if(front == (rear+1)%elem.length){return true;//中间空出一个空间的时候,就是满}return false;}}
}

2. 双端队列

双端队列(deque)是指允许两端都可以进行入队和出队操作的队列,deque 是 “double ended queue” 的简称。那就说明元素可以从队头出队和入队,也可以从队尾出队和入队
在这里插入图片描述
Deque是一个接口,必须使用LinkedList实例化对象.
在这里插入图片描述

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

3. 队列与栈的综合

3.1 用栈实现队列

在用栈实现队列的时候,核心思想把握住一句话:出队列的顺序和出栈的顺序相反,对头的元素对应栈底的元素.
在这里插入图片描述

OJ链接

class MyQueue2 {//需要用两个栈来实现一个队列Stack<Integer> stack1;Stack<Integer> stack2;public MyQueue2() {stack1 = new Stack<>();stack2 = new Stack<>();}public void push(int x) {stack1.push(x);//入队列的时候就入第一个栈就可以}public int pop() {int value = 0;if (stack2.empty()){//如果stack2为空的时候,就把stack1的元素全部倒到2中//是因为出队列的顺序和出栈的顺序相反,对头的元素对应栈底的元素while(!stack1.empty()){stack2.push(stack1.pop());}value = stack2.peek();stack2.pop();//出2的栈顶元素}else {//如果不为空,直接出栈顶元素value = stack2.peek();stack2.pop();}return value;}public int peek() {int value = 0;if (stack2.empty()){while(!stack1.empty()){stack2.push(stack1.pop());}value = stack2.peek();}else {value = stack2.peek();}return value;//和pop原理一样,只不过没有元素出栈}public boolean empty() {//两个栈都为空的时候,队列为空if (stack1.empty() && stack2.empty()){return true;}else {return false;}}}

3.2 用队列实现栈

这道题的核心是:队列中最后一个元素对应栈顶的元素,所以要让队尾的元素露出来.
在这里插入图片描述
OJ链接

class MyStack {Queue<Integer> queue1;Queue<Integer> queue2;//使用两个队列来完成栈的实现public MyStack() {queue1 = new LinkedList<>();queue2 = new LinkedList<>();}public void push(int x) {if (empty()){//空就往任意一个队列中添加queue1.offer(x);return;//记得返回}if (!queue1.isEmpty()){//谁不为空,就往谁添加queue1.offer(x);}else {queue2.offer(x);}}public int pop() {if (empty()){return -1;}if (queue1.isEmpty()){while(queue2.size() != 1){//poll到队列中只有1个元素,目的是让队列中的元素与栈顶元素对应起来queue1.offer(queue2.poll());}return queue2.poll();//弹出只剩一个元素的队列}else {while(queue1.size() != 1){queue2.offer(queue1.poll());}return queue1.poll();}}public int top() {if (empty()){return -1;}int value = 0;//利用vlaue保存peek的值if (queue1.isEmpty()){while(queue2.size() != 1){queue1.offer(queue2.poll());}value = queue2.peek();queue1.offer(queue2.poll());//先peek保存,再poll到另一个队列中return value;}else {while(queue1.size() != 1){queue2.offer(queue1.poll());}value = queue1.peek();queue2.offer(queue1.poll());return value;}}public boolean empty() {return queue1.isEmpty() && queue2.isEmpty();}}

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

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

相关文章

C语言分支语句

一、什么是语句 C语句可分为以下五类&#xff1a; 表达式语句 函数调用语句 控制语句 复合语句 空语句 本周后面介绍的是控制语句。 控制语句用于控制程序的执行流程&#xff0c;以实现程序的各种结构方式&#xff0c;它们由特定的语句定义符组成&#xff0c;C语 言有…

android 资源文件混淆

AGP7.0以上引用AndResGuard有坑 记录下 在项目的build.gradle中添加如下 buildscript {ext.kotlin_version "1.4.31"repositories {google()jcenter()maven {url "https://s01.oss.sonatype.org/content/repositories/snapshots/"}}dependencies {class…

JQuery(二)---【使用JQuery对HTML、CSS进行操作】

零.前言 JQuery(一)---【JQuery简介、安装、初步使用、各种事件】-CSDN博客 一.使用JQuery对HTML操作 1.1获取元素内容、属性 使用JQ可以操作元素的“内容” text()&#xff1a;设置或返回元素的文本内容html()&#xff1a;设置或返回元素的内容(包括HTML标记)val()&#…

Flask Python Flask-SQLAlchemy中数据库的数据类型、flask中数据可的列约束配置

Flask Python Flask-SQLAlchemy中数据库的数据类型、flask中数据可的列约束配置 SQLAlchemy官方文档地址实战的代码分享数据类型列约束配置自定义方法 SQLAlchemy官方文档地址 SQLAlchemy官方文档地址 实战的代码分享 Flask-SQLAlchemy框架为创建数据库的实例提供了一个基类…

Android Studio学习16——Activity跳转时的参数传递

传递数据——example 传递对象类型的数据——example 传递 接收 回传数据——example

PicGo + Gitee + VsCode - 搭建私人图床

文章目录 前言搭建图床VsCode 安装插件安装 PicGo准备 Gitee 图床测试 尾声 前言 本人是一个重度 vimer&#xff0c;并且喜欢客制化一些东西… Typora 固然好用&#xff0c;但不支持 vim…发现 vscode 中既可以使用 vim&#xff0c;也可以 md&#xff0c;用起来比较舒服.因此…

自动驾驶定位算法:基于多传感器融合的状态估计(muti-Sensors Fusion)

自动驾驶定位算法&#xff1a;基于多传感器融合的状态估计(muti-Sensors Fusion) 附赠自动驾驶学习资料和量产经验&#xff1a;链接 1、传感器(Sensor)选取 自动驾驶系统中用于状态估计(State Estimation)的常用传感器包括GPS/GNSS、IMU、激光雷达(Lidar)。 状态估计(State E…

Android JNI调试总结

1、确保NDK和CMake已经安装 新建能编译APK的工程&#xff0c;工程中添加相关ndk目录 2、添加C模块 添加完成后&#xff0c;工程目录自动更新&#xff0c;build.gradle导入了so编译器 修改build.gradle中添加相关gcc编译器如下 externalNativeBuild { cmake { abiFilters a…

python学习25:python中的元组(tuple)

python中的元组(tuple) 1.什么是元组&#xff1f; 元组也是容器数据类型的一种&#xff0c;同列表几乎是一样的&#xff0c;都是可以在里面封装多个&#xff0c;不同类型的元素在内&#xff1b;与列表最大的不同就是&#xff1a; 元组一旦被定义&#xff0c;就不能修改 2.元组…

头盔检测 | 基于Caffe-SSD目标检测算法实现的建筑工地头盔检测

项目应用场景 面向建筑工地头盔检测场景&#xff0c;使用深度学习 Caffe SSD 目标检测算法&#xff0c;基于 C 实现。 项目效果 项目细节 > 具体参见项目 README.md (1) 安装 Caffe SSD(2) 执行训练 sh examples/Hardhat/SSD300/train_SSD300.sh (3) 部署算法 项目获取 h…

vitepress系列-05-其他优化设置

其他优化设置 设置底部上一页和下一页 设置&#xff1a; import { defineConfig } from vitepress// https://vitepress.dev/reference/site-config export default defineConfig({lang: en-US,title: "东东爱编码的技术博客",description: "记录日常学习点点…

IO流

一、IO概述 1&#xff0e;什么是IO流? 存储和读取数据的解决方案l: inputo: output流∶像水流一样传输数据 2.IO流的作用? 用于读写数据&#xff08;本地文件&#xff0c;网络) 3.IO流按照流向可以分类哪两种流? 输出流:程序 - > 文件 输入流:文件 - > 程…

布隆过滤器详解及java实现

什么是布隆过滤器&#xff1f; 布隆过滤器&#xff08;Bloom Filter&#xff09;是一种数据结构&#xff0c;用于判断一个元素是否属于一个集合。它的特点是高效地判断一个元素是否可能存在于集合中&#xff0c;但是存在一定的误判率。 布隆过滤器的基本原理是使用一个位数组…

测试工程师求职是选自研公司还是选外包公司呢?

大家好&#xff0c; 今天我们一起来聊一聊测试工程师求职是选自研公司&还是选外包公司呢&#xff1f; 今天来谈谈我的个人看法&#xff0c;作为一个在测试岗位上多年的我来说&#xff0c;自研公司比较好&#xff0c;外包公司其实也不会差。各自都有特点特色&#xff0c;根据…

MIT6.828 Lab1 Xv6 and Unix utilities

2023MIT6.828 lab-1 官方地址 一、sleep 实验内容 调用sleep&#xff08;系统调用&#xff09;编写用户级别程序能暂停特定时常的系统滴答程序保存在user/sleep.c 实验过程 xv6的参数传递 查看官方文档提示的文件中&#xff0c;多采用如下定义&#xff1a; int main(in…

Idea打包jar包的多种方式(解决MANIFEST.MF被覆盖的问题)

目录 生成jar文件 方式一&#xff1a;打包成一个总的jar文件 方式二&#xff1a;打包的jar文件和第三方jar文件分开 生成jar文件 打开“文件->项目结构-构建” 点击“”选择“jar->from modules ....” 弹出“从模块创建 jar” 方式一&#xff1a;打包成一个总的jar…

海纳斯删除广告位

找到文件 vim /var/www/html/home.php 删除代码段 <div class"adleft" id"adleftContainer"><button onclick"closeAd()">关闭</button><a href"https://www.ecoo.top/ad.html" target"_blank">&l…

JAVA—抽象—定义抽象类Converter及其子类WeightConverter

同样&#xff0c;我们由这道题引出抽象类&#xff0c;抽象方法这个概念。 按下面要求定义类Converter及其子类WeightConverter 定义抽象类&#xff1a;Converter&#xff1a; 定义一个抽象类Converter&#xff0c;表示换算器&#xff0c;其定义的如下&#xff1a; 一个私有…

海外仓的出入库流程有什么痛点?位像素海外仓系统怎么提高出入库效率?

随着跨境电商的蓬勃发展&#xff0c;海外仓是其中不可或缺的一个关键环节。而货物的出库与入库则是海外仓管理中的一个核心业务流程&#xff0c;它的运作效率直接影响到整个跨境物流的效率和客户体验。今天&#xff0c;让我们具体来看一看关于海外仓出入库的流程&#xff0c;其…

JVM内存性能调优思路之:通过GC log、Thread Dump 、Heap Dump分析内存使用说明

文章目录 一. 各日志概述1. Garbage Collection Log - 找到GC规律2. 线程转储(Thread dump) - 分析&#xff08;快照&#xff09;线程状态3. 堆转储(Heap dump) - APP某刻内存使用全貌 二. 命令1. 程序的gc日志2. 线程转储3. 堆转储 概述 在 Java 虚拟机中&#xff0c;(GC) Gar…