当前位置: 首页 > news >正文

JavaDS —— 栈 Stack 和 队列 Queue

栈的概念

栈是一种先进后出的线性表,只允许在固定的一端进行插入和删除操作。
进行插入和删除操作的一端被称为栈顶,另一端被称为栈底

栈的插入操作叫做进栈/压栈/入栈
栈的删除操作叫做出栈

在这里插入图片描述
现实生活中栈的例子:
在这里插入图片描述

栈的模拟实现

下面是Java集合类给我们提供的栈的方法:

在这里插入图片描述

模拟实现顺序栈

我们通过数组来模拟实现栈。

构建数组栈

我们需要两个成员变量,一个是数组,另一个是记录当前的数据个数。

    public int[] elem;public int usedSize;public MyStack() {elem = new int[5];}

push

要考虑扩容问题

    private boolean isFull() {if(usedSize == elem.length) {return true;}return false;}private void grow() {elem = Arrays.copyOf(elem,2*elem.length);}public void push(int val) {if(isFull()) {grow();}elem[usedSize++] = val;}

isEmpty

判断栈是否为空:

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

pop

设置自定义异常:

public class PopException extends RuntimeException{public PopException() {super();}public PopException(String message) {super(message);}
}

删除栈顶的同时,还会返回删除的元素

    private void checkPop() throws PopException{if(isEmpty()) {//抛异常throw new PopException("栈已空,无法删除!!!");}}public int pop() {try {checkPop();int ret = elem[usedSize-1];usedSize--;return ret;} catch (PopException e) {e.printStackTrace();}return -1;}

peek

获取栈顶元素 但是不删除

    public int peek() {try {checkPop();return elem[usedSize-1];} catch (PopException e) {e.printStackTrace();}return -1;}

链式栈

链式栈顾名思义就是利用链表来保存栈

假设使用单链表制作链式栈,建议使用头插和头删法来进行push和pop操作,peak直接把头节点的值获取即可,这样时间复杂度可以为O(1);但是如果你使用尾插和尾删就是以尾节点的位置作为栈顶,在push,pop 和 peak 的时候,时间复杂度为O(N)

假设使用双向无头循环链表,无论是选择头插头删还是尾插尾删作为push与pop,时间复杂度都是O(1)

这里就不演示链式栈的代码。

Stack 的使用

在这里插入图片描述
push 入栈;pop 出栈;peak 获取栈顶元素;empty 是否为空;size 这个获取有效元素的方法是在Vector 中的,search 找到某元素距离栈顶元素的距离多少(栈顶元素记为1,然后一直到目标元素)

栈、虚拟机栈、栈帧有什么区别呢?

栈是我们的数据结构的其中一种形式,虚拟机栈是JVM虚拟机的一块内存,栈帧是运行一个方法或者函数的时候计算机给它开辟的内存。

队列的概念

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾(Tail/Rear) 出队列:进行删除操作的一端称为队头(Head/Front)

队列类似我们生活中的排队。

在这里插入图片描述

队列的模拟实现

在这里插入图片描述
上面是Java集合类给我们提供的队列的方法,其中add和offer都是入队操作,poll 和 remove 都是出队操作,element 和 peek 都是获取队列头部的元素。

它们主要的区别是会不会抛异常~~ 下面有详细的介绍:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


链式队列

这里我们将使用数组来模拟实现队列,并且这里只实现下图所示的方法:
在这里插入图片描述

size 和 isEmpty 是队列继承的方法,并且队列没有重写这两个方法,所以上面的IDEA直接看队列的Structure 是看不到的。


假设我们使用单链表为基础,该怎么实现队列?
假设入队采用尾插,那要出队即使用头删即可
出队列使用单链表的头删即可,时间复杂度为O(1)
入队列使用尾插,一般情况下,单链表实现尾插首先要找到尾,然后才是开始插入,这时候时间复杂度就尾O(N),不是最优解,我们可以加一个尾指针保存好尾节点,这样就方便我们快速进行尾插操作。

假设入队使用头插,那出队的时候就需要使用尾删
这时候就不好弄了,即使你有尾指针在进行尾删的时候还是需要遍历链表找到尾节点的前一个结点才能完成尾删,这时候你可能会认为再定义一个指针,这就很麻烦了。

所以单链表构建队列的话,限制条件有点大,但是使用上一片文章的双向链表(无头双向循环链表 LinkedList) ,就可以随意选取一端作为入队,另一端作为出队。

这里我们入队采用尾插,出队采用头删:

public class MyQueue {public static class ListNode {public int val;public ListNode prev;public ListNode next;public ListNode(int val) {this.val = val;}}public ListNode head;public ListNode last;//入队public boolean offer(int data) {ListNode node = new ListNode(data);if(isEmpty()) {last = head = node;} else {last.next = node;node.prev = last;last = node;}return true;}public boolean isEmpty() {return head == null;}//出队public int poll() {if(isEmpty()) {return -1;}int ret = head.val;if(head.next != null) {head.next.prev = null;}head = head.next;return ret;}//求结点个数public int size() {ListNode cur = head;int count = 0;while(cur != null) {count++;cur = cur.next;}return count;}//获取队头元素public int peek() {if(isEmpty()) {return -1;}return head.val;}
}

这里要注意出队的代码,如果只有一个结点的情况下,你进行删除后就没有结点了,head.next.prev = null 这行代码就会发生报错。

顺序队列

顺序队列我们采用数组来实现队列,这时候我们就要思考一个问题,在不断的出队入队的情况下怎么保证空间尽可能地利用起来?
假设数组的数据已满装满的情况下,我们一直出队直到数组变空的话,怎么利用起来前面的空间?

在这里插入图片描述

循环队列

这时候我们就需要使用循环队列让队列的空间有效的利用起来。

法1 :定义一个成员变量,usedSize 记录使用了多少的空间
法2 : 定义一个标记符,记录空间是否已满
法3 :浪费一个空间,通过数学公式判断队列是否已满

在这里插入图片描述
一般情况下,我们会认为这就是队列空和满的两种状态,但是这两种状态都是 front == near,怎么办?
根据法1,我们可以记录使用了多少空间的usedSize 来判断队列是否已满,即 usedSize = 数组的长度即可认为队列已满
根据法2,我们使用标记符,首先 将标记符记为 -1,认为队列没满,当front 与near 再次相遇时,标记符乘 -1 变为1 ,判断 队列 已满,如果下一个操作时出队,那标记符再自乘 -1变回 -1 ,当front 与 rear 再次相遇时标记符自乘 -1 变为1 表示队列已满,以此类推,这里大家可以自由发挥。


第三个方法是利用队列自身来进行判断,当 rear 的下一个就是 front 的时候(即 ( rear + 1 ) % 数组长度 == front),就判断队列已满,这需要我们浪费队列的一个空间。
在这里插入图片描述


如何让rear 和 front 循环起来呢?即rear 的下标该如何制定呢?
这里有一个公式,当 rear 要 自增的时候,新的 rear = ( rear + 1 ) % 数组长度就是此时rear 对应的实际下标,当 rear 为 7 时,rear 向下移动一格时,新的 rear 就是 ( 7 + 1 ) % 8 = 0, 正好就是 7 下一个的下标值 0


问题拓展 (数组下标循环的小技巧)

下标往后移动(offset 小于 array.length): index = (index + offset) % array.length

在这里插入图片描述


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

array.length - offset 其实就是变相地让 小标变成向后 移动。
在这里插入图片描述


顺序队列的代码
public class MyQueue {int front;int rear;int[] elem;public MyQueue() {elem = new int[4];}//入队public boolean offer(int data) {if(isFull()) {return false;}elem[rear] = data;rear = (rear + 1) % elem.length;return true;}//队列是否已满private boolean isFull() {return (rear + 1) % elem.length == front;}//队列是否为空public boolean isEmpty() {return rear == front;}//出队public int poll() {if(isEmpty()) {return -1;}int ret = elem[front];front = (front + 1) % elem.length;return ret;}//求元素个数public int size() {int count = 0;for (int i = front; i < rear; i++) {count++;}return count;}//获取队头元素public int peek() {if(isEmpty()) {return -1;}return elem[front];}
}

Queue

在这里插入图片描述
上面是我们常用的队列方法

在这里插入图片描述
队列Queue本质上是一个接口,所以Queue 不能被实例化,那如何使用?

Deque (双端队列)

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

在这里插入图片描述
在这里插入图片描述
我们可以发现 Deque 其实是继承了 Queue 接口,但是还是一个接口,还是不能实例化,那怎么使用?请看下面解说。

LinkedList 和栈与队列的关系

在这里插入图片描述

在这里插入图片描述

LinkedList 有很多接口其中包括了 Deque ,而Deque 这个接口其实继承了 Queue ,也就是队列,所以我们可以实例化 一个LinkedList 对象然后通过 Queue 接收就可以使用普通队列的方法,同理,通过实例化一个LinkedList 对象然后通过 Deque 接收就可以使用双端队列的方法


    public static void main(String[] args) {LinkedList<Integer> linkedList = new LinkedList<>();linkedList.push(1);linkedList.push(2);linkedList.push(3);System.out.println(linkedList.peek());System.out.println(linkedList.pop());System.out.println(linkedList.peek());}

在这里插入图片描述

LinkedList还可以当成栈来使用,也就是说LinkedList还包含栈的方法,自身功能很强大。

小结:
LinkedList 不仅可以作为不带头的双向循环链表使用,还可以当成栈或者队列使用。


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

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

习题链接:
http://t.csdnimg.cn/aV91m

相关文章:

JavaDS —— 栈 Stack 和 队列 Queue

栈的概念 栈是一种先进后出的线性表&#xff0c;只允许在固定的一端进行插入和删除操作。 进行插入和删除操作的一端被称为栈顶&#xff0c;另一端被称为栈底 栈的插入操作叫做进栈/压栈/入栈 栈的删除操作叫做出栈 现实生活中栈的例子&#xff1a; 栈的模拟实现 下面是Jav…...

C++进阶:继承和多态

文章目录 ❤️继承&#x1fa77;继承与友元&#x1f9e1;继承和静态成员&#x1f49b;菱形继承及菱形虚拟继承&#x1f49a;继承和组合 ❤️多态&#x1fa77;什么是多态&#xff1f;&#x1f9e1;多态的定义以及实现&#x1f49b;虚函数&#x1f49a;虚函数的重写&#x1f499…...

【八大排序】java版(上)(冒泡、快排、堆排、选择排序)

文章目录 一、冒泡排序(重点)思路代码 二、快排(面试重点)思路代码 三、堆排序(面试重点)思路代码 四、选择排序思路代码 一、冒泡排序(重点) 思路 前后两两数据进行比较&#xff0c;小的数据往前走&#xff0c;大的数据往后走&#xff0c;每一轮结束之后&#xff0c;最大的数…...

.Net Core 微服务之Consul(二)-集群搭建

引言: 集合上一期.Net Core 微服务之Consul(一)(.Net Core 微服务之Consul(一)-CSDN博客) 。 目录 一、 Consul集群搭建 1. 高可用 1.1 高可用性概念 1.2 高可用集群的基本原理 1.3 高可用集群的架构设计 1.3.1 主从复制架构 1.3.2 共享存储架构 1.3.3 负载均衡…...

C++ --> 类和对象(二)

前言 在前面简单的介绍了OOP&#xff0c;什么是类&#xff0c;在类中的this指针。接下来就深入理解类和对象。 默认成员函数 默认构造函数&#xff1a;用于在创建对象时初始化对象的成员变量。默认拷贝构造函数&#xff1a;用于使用已存在的对象来初始化新创建的对象。默认析构…...

利用宝塔安装一套linux开发环境

更新yum&#xff0c;并且更换阿里镜像源 删除yum文件 cd /etc/yum.repos.d/ 进入yum核心目录 ls sun.repo rm -rf * 删除之前配置的本地源 ls 配置阿里镜像源 wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo 配置扩展包 wge…...

VB 实例:掌握 Visual Basic 编程的精髓

VB 实例:掌握 Visual Basic 编程的精髓 引言 Visual Basic(简称VB)是一种由微软开发的高级编程语言,它结合了易于使用的界面和强大的编程功能,使得初学者和专业人士都能快速开发Windows桌面应用程序。本文将通过一系列实例,深入探讨VB编程的基础知识和高级技巧,帮助读…...

层次分析法:matlab代码实现

计算权重&#xff1a; 一、算术平均法 关于矩阵&#xff1a; 1、矩阵的输入写法 [ ; ; ]同行用空格或逗号隔开&#xff0c;不同行用分号间隔 2、矩阵求和 默认按列求和 asum(E) 等同于 asum(E,1) 得到行向量 按行求和 asum(E,2) 得到列向量 对整个矩阵求和 asum(E,"all&…...

07-7.5.3 处理冲突的方法

&#x1f44b; Hi, I’m Beast Cheng &#x1f440; I’m interested in photography, hiking, landscape… &#x1f331; I’m currently learning python, javascript, kotlin… &#x1f4eb; How to reach me --> 458290771qq.com 喜欢《数据结构》部分笔记的小伙伴可以…...

几何距离与函数距离:解锁数据空间中的奥秘

几何距离&#xff1a;直观的空间度量 几何距离&#xff0c;顾名思义&#xff0c;是我们在几何学中熟悉的距离概念&#xff0c;如欧几里得距离、曼哈顿距离和切比雪夫距离等。这些距离度量直接反映了数据点在多维空间中的位置关系。 欧几里得距离&#xff1a;最为人熟知的几何距…...

LabVIEW的Actor Framework (AF) 结构介绍

LabVIEW的Actor Framework (AF) 是一种高级架构&#xff0c;用于开发并发、可扩展和模块化的应用程序。通过面向对象编程&#xff08;OOP&#xff09;和消息传递机制&#xff0c;AF结构实现了高效的任务管理和数据处理。其主要特点包括并发执行、动态可扩展性和强大的错误处理能…...

gitlab 搭建使用

1. 硬件要求 ##CPU 4 核心500用户 8 核心1000用户 ##内存 4 G内存500用户 8 G内存1000用户 2. 下载 链接 3. 安装依赖 yum -y install curl openssh-server postfix wget 4. 安装gitlab组件 yum -y localinstall gitlab-ce-15.9.3-ce.0.el7.x86_64.rpm 5. 修改配置文…...

探索JT808协议在车辆远程视频监控系统中的应用

一、部标JT808协议概述 随着物联网技术的迅猛发展&#xff0c;智能交通系统&#xff08;ITS&#xff09;已成为现代交通领域的重要组成部分。其中&#xff0c;车辆远程监控与管理技术作为ITS的核心技术之一&#xff0c;对于提升交通管理效率、保障道路安全具有重要意义。 JT8…...

视频使用操作说明书-T80005系列视频编码器如何对接海康NVR硬盘录像机,包括T80005系列高清HDMI编码器、4K超高清HDMI编码器

视频使用操作说明书-T80005系列视频编码器如何对接海康NVR硬盘录像机&#xff0c;包括T80005系列高清HDMI编码器、4K超高清HDMI编码器。 视频使用操作说明书-T80005系列视频编码器如何对接海康NVR硬盘录像机&#xff0c;包括T80005系列高清HDMI编码器、4K超高清HDMI编码器 同三…...

keep-alive缓存组件

keep-alive缓存组件是Vue.js中的一个特殊组件&#xff0c;主要用于缓存内部组件的数据状态&#xff0c;以提高应用的性能和用户体验。以下是关于keep-alive缓存组件的详细解析&#xff1a; 一、作用 缓存组件状态&#xff1a;当组件在<keep-alive>内部切换时&#xff0…...

Linux上如何安装ffmpeg视频处理软件

在Linux上安装ffmpeg需要以下步骤&#xff1a; 更新系统 在开始安装之前&#xff0c;首先需要更新系统以获取最新的软件包列表和版本。在终端中执行以下命令&#xff1a; sudo apt update sudo apt upgrade安装依赖库 ffmpeg依赖于一些库和工具&#xff0c;需要先安装它们。在…...

element如何实现自定义表头?

有时候我们需要实现自定义表头,例如表头里加按钮啥的,这时候就需要用到自定义表头,但是官方对自定义表头的使用写的还是比较简单,今天就来详细说说 在需要使用自定义表头的表头上使用:render-header来启用自定义表头: <el-table-column :render-header="button&…...

OTP防重放攻击

OTP本意是一次性口令&#xff0c;比如邮箱验证码&#xff0c;短信验证码&#xff0c;或者根据totp或者hotp生成的默认30秒一变的6位数字。 不过开发者要注意&#xff0c;必须要在验证成功后失效那个验证码&#xff0c;不然就会导致重放攻击。 对于邮箱验证码&#xff0c;服务器…...

Oracle数据库加密与安全

Wallet简介&#xff1a; Oracle Wallet(即内部加密技术TDE( Transparent DataEncryption&#xff09; TDE是 Oracle10gR2中推出的一个新功能,使用时要保证Oracle版本是在10gR2或者以上 Wallet配置&#xff1a; 1.创建一个新目录&#xff0c;并指定为Wallet目录 /home/oracle…...

【YOLO格式的数据标签,目标检测】

标签为 YOLO 格式&#xff0c;每幅图像一个 *.txt 文件&#xff08;如果图像中没有对象&#xff0c;则不需要 *.txt 文件&#xff09;。*.txt 文件规格如下: 每个对象一行 每一行都是 class x_center y_center width height 格式。 边框坐标必须是 归一化的 xywh 格式&#x…...

Memcached内存碎片清理术:优化缓存性能的策略

标题&#xff1a;Memcached内存碎片清理术&#xff1a;优化缓存性能的策略 内存碎片是Memcached在长期运行过程中常见的问题&#xff0c;它会降低缓存效率并影响性能。作为高效的分布式内存缓存系统&#xff0c;Memcached提供了多种内存碎片整理策略。本文将详细介绍这些策略&…...

禁止使用存储过程

优质博文&#xff1a;IT-BLOG-CN 灵感来源 什么是存储过程 存储过程Stored Procedure是指为了完成特定功能的SQL语句集&#xff0c;经编译后存储在数据库中&#xff0c;用户可通过指定存储过程的名字并给定参数&#xff08;如果该存储过程带有参数&#xff09;来调用执行。 …...

Flink异常:org/apache/hadoop/hive/ql/parse/SemanticException

在flink项目中跑 上面这段代码出现如下这个异常&#xff0c; java.lang.NoClassDefFoundError: org/apache/thrift/TException 加上下面这个依赖后不报错 <dependency> <groupId>org.apache.thrift</groupId> <artifactId>libthrift</artifactId…...

Java:构造函数与对象

第一章&#xff1a;构造函数揭秘 —— 创造者的第一次触碰 构造函数&#xff0c;顾名思义&#xff0c;是用于创建和初始化对象的特殊方法。它没有返回类型&#xff0c;名字与类名一致。构造函数是对象诞生的第一步&#xff0c;也是最至关重要的一步。让我们通过一个生动的例子…...

Leetcode(经典题)day1

删除有序数组中的重复项|| 80. 删除有序数组中的重复项 II - 力扣&#xff08;LeetCode&#xff09; 和之前的删除有序数组中的重复项|相似&#xff0c;这里是要求最多出现两次&#xff0c;所以多加一个变量来记录出现次数即可&#xff0c;整体上还是使用双指针&#xff0c;…...

k8s record 20240710 监控

不是adaptor 是opetator 案例 监控有了&#xff0c;日志搜集呢&#xff1f; 一、kubelet 的小弟 kubelet — 负责维护容器的生命周期&#xff0c;节点和集群其他部分通信 cAdvisor 集成在 Kubernetes 的 kubelet 中&#xff0c;能够自动发现和监控集群中所有的容器。dockers…...

pdf工具

iLovePDF | 为PDF爱好者提供的PDF文件在线处理工具 https://www.ilovepdf.com/zh-cn 图片 pdf 合并成一个pdf也可以拆分...

百度文心4.0 Turbo开放,领跑国内AI大模型赛道!

百度文心4.0 Turbo开放&#xff0c;领跑国内AI大模型赛道&#xff01; 前言 文心一言大模型 就在7月5日&#xff0c;在2024世界人工智能大会 (WAIC) 上&#xff0c;百度副总裁谢广军宣布文心大模型4.0 Turbo正式向企业客户全面开放&#xff01;这一举动直接引发了业界的关注。那…...

Vue3 defineProps的使用

1.什么是defineProps defineProps是Vue3中的一种新的组件数据传递方式&#xff0c;可以用于在子组件中定义接收哪些父组件的props。当父组件的props发生变化时&#xff0c;子组件也会随之响应。 2.如何使用defineProps&#xff1f; 在子组件中可以使用defineProps声明该组件…...

面向对象进阶基础练习

Java学习笔记&#xff08;新手纯小白向&#xff09; 第一章 JAVA基础概念 第二章 JAVA安装和环境配置 第三章 IntelliJ IDEA安装 第四章 运算符 第五章 运算符联系 第六章 判断与循环 第七章 判断与循环练习 第八章 循环高级综合 第九章 数组介绍及其内存图 第十章 数…...

如何用vs做网站/2023年4 5月份疫情结束吗

《单片机C语言项式教程》期末复习试卷10套一、选择题(每题2分&#xff0c;共20分)1、所谓CPU是指(  )A、运算器和控制器  B、运算器和存储器 C、输入输出设备   D、控制器和存储器2、访问片外数据存储器的寻址方式是( )A、立即寻址 B、寄存器寻址 C、寄存器间接寻址 D、…...

广州网站建设泸州/网络推广营销网

文章目录1. 安装JDK2.安装Gitblit2.1 下载Gitblit解压配置运行3.常见错误启动时报Unsupported major.minor version 51.0电脑关机后&#xff0c;再次运行gitblit-1.9.1/gitblit.cmd 批处理文件闪退1. 安装JDK git服务器依赖java&#xff0c;需要先安装java并配置环境变量&…...

住房各城乡建设网站/泰安网站seo推广

一、源码特点 1、采用典型的三层架构进行开发、模板分离&#xff0c;支持生成静态 伪静态.、购物车、登陆验证、divcss、js等技术二、功能介绍 1、本源码是一个超市在线购物商城源码,该网上商城是给超市便利店等零售批发实体店定制的网上商城&#xff0c;主要针对周边配送&…...

做外汇看什么网站/阿里云域名注册入口官网

由原来的使用VMware转到使用Virtual Box&#xff0c;发现其vim编辑器不是特别好用&#xff0c;需要进行一下更改设置&#xff1a; 1、使用命令删除vim&#xff0c;sudo apt-get remove vim-common 2、删除后重新安装&#xff0c;命令&#xff1a;sudo aptitude install vim 3、…...

广州白云手机网站建设/中国万网官网

GHpython 脚本对于数据输入的问题 分为item&#xff0c;list&#xff0c;data tree 在此就搬一下官网的例子 将datatree 遍历转换为列表可以用Flatten Tree 组件。...

p2p网站建设cms/网络seo是什么

Vue--关于点击当前路由&#xff0c;视图无法更新的解决方案参考文章&#xff1a; &#xff08;1&#xff09;Vue--关于点击当前路由&#xff0c;视图无法更新的解决方案 &#xff08;2&#xff09;https://www.cnblogs.com/first-time/p/7155914.html 备忘一下。...