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…

C++实现更改8位无符号整形的第n比特位值为1或0

value为8位无符号整形&#xff0c;如何更改其第n比特位的值&#xff1f;比如&#xff1a;value为243&#xff0c;二进制表示为&#xff1a; 1111 0011 如何将value更改为&#xff1a; 1011 0011 即在不改变其它比特位值的情况下&#xff0c;仅仅通过更改需要更改的比特位的…

树莓派游戏简单应用实例

树莓派是一款小巧的单板电脑&#xff0c;其工作原理是通过将电子元件如处理器、内存、存储器、输入输出接口等集成在一块电路板上&#xff0c;通过外部连接器与外部设备进行通信。 树莓派设备的工作原理主要包括以下几个方面&#xff1a; 处理器&#xff1a;树莓派采用ARM架构…

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框架为创建数据库的实例提供了一个基类…

数据库系统概论

数据库系统概论 一、引言 数据库系统作为现代信息技术的重要组成部分&#xff0c;已经深入到社会生活的各个领域。无论是商务领域、科技发展&#xff0c;还是国家政府部门&#xff0c;数据库系统都发挥着举足轻重的作用。通过高效、稳定、安全的数据存储和管理&#xff0c;数…

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…

【QT教程】QT6 Web开发入门

QT6 Web开发入门 使用AI技术辅助生成 QT界面美化视频课程 QT性能优化视频课程 QT原理与源码分析视频课程 QT QML C扩展开发视频课程 免费QT视频课程 您可以看免费1000个QT技术视频 免费QT视频课程 QT统计图和QT数据可视化视频免费看 免费QT视频课程 QT性能优化视频免费看 免费…

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: "记录日常学习点点…

进入IT行业:零基础者的全面指南

在当今快速发展的技术时代&#xff0c;信息技术&#xff08;IT&#xff09;行业成为了许多人向往的领域。即便没有任何相关背景知识&#xff0c;个人仍然可以通过具体的方法和技巧成功进入这一行业。本文将详细介绍如何从零开始&#xff0c;通过自学、实践和网络建立&#xff0…

IO流

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

布隆过滤器详解及java实现

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

贪心算法|134.加油站

力扣题目链接 class Solution { public:int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {int curSum 0;int min INT_MAX; // 从起点出发&#xff0c;油箱里的油量最小值for (int i 0; i < gas.size(); i) {int rest gas[i] - cost[…

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

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