【数据结构_9】栈和队列

队列 Queue 一个方向进,一个方向出

Queue队列提供的核心方法:

入队列:offer add

出队列:poll remove

取队首元素: peek element

前面一列发生错误是返回null  后面一列发生错误时抛出异常

Queue是否能够使用isEmpty()/size 等这样的方法呢?

答案:是可以的,因为Queue接口继承自Collection接口,而Collection接口实现了这一系列方法。

因此,判定队列是否为空也就有了两种表示方法:

        //判定队列是否为空if(queue.peek()==null){}if(queue.isEmpty()){}

一、模拟实现队列

package Queue;
//基于单链表实现的队列
public class MyQueue {//链表的一个节点public class Node{public String val;public Node next;//提供构造方法public Node(String val) {this.val = val;this.next = null;}}//把队列的头部和尾部都记录下来//基于俩表实现队列//1.入队—>尾插//2.出队—>尾删private Node head;private Node tail;//入队public void offer(String val) {Node newNode = new Node(val);//考虑特殊情况 如果链表中没有元素if(head== null){head = newNode;tail = newNode;return;}//一般情况tail.next = newNode;tail = newNode;}//出队列public String poll(){//如果链表是空的if(head == null){return null;}//一般情况//保存头部节点的值//接下来把这个节点删除后,需要返回这个值String val = head.val;head = head.next;//如果链表的节点数目超出一个,删掉一个元素,不影响tail的指向//但是,如果链表的节点数目只有一个,删掉这个元素,此时tail就应该指向nullif(head.next== null){tail = null;}return  val;}//取队首元素public String peek(){//如果链表是空的if(head == null){return null;}return head.val;}//判断队列是否为空public Boolean isEmpty(){return head == null;}//计算队列的长度public int size(){int size = 0;for(Node cur = head;cur!= null;cur =cur.next){size++;}return size;}//一些测试public static void main(String[] args) {MyQueue queue = new MyQueue();queue.offer("a");queue.offer("b");queue.offer("c");queue.offer("d");queue.offer("e");System.out.println(queue.peek());System.out.println(queue.poll());System.out.println(queue.peek());System.out.println(queue.poll());}
}

二、数组实现队列

        //这是一个基于数组的队列Queue<Integer> queue1 = new ArrayDeque<>();//基于数组实现的双端队列

首先先创建一个数组new int[8]

和顺序表设定类似,不是一上来这8个格子都被使用了,而是随着后续入队列逐渐使用。

由于是一个队列,使用head下标记录队首位置,使用tail下标记录队尾元素的下一个位置。

初始情况下,head 和tail都指向0位置,此时认为是一个空的队列。

队列能入也能出,出队列,得从head的位置进行考虑,如果是按照顺序表头删的做法,此时就需要搬运大量的元素,实现队列的效率就太低了。

所以这里的出队列我们选择用逻辑删除:这里的删除,不是真的把数据给改成别的,而是在逻辑上将其标记成无效。

此处也是往后移动head的位置,由于[head,tail)构成前闭后开开区间,当head++之后,之前head指向元素就被视为无效了。

当tail到达数组末尾,此时是否就意味着队列满了呢?并非。数组版本的队列,就像是把数组弯过来,头尾相接,构成了一个环。也就是“循环队列”

如果在这个循环队列中,队列满了怎么办?有人说,可以通过head 和tail是否重合来判断队列是否满了,但是最初队列为空的时候,head和tail也是重合的。

如何区分上述队列是空的还是满的呢?

此时我们有两种方案来解决这个问题:

方案一:直接浪费一个格子,当tail走到head的前一个位置的时候哦,就视为队列满了,确保再队列满的时候,tail就是head的前一个位置。队列为空的时候,tail与head才重合。

方案二:引入一个size变量即可,size ==0 就是空 size = arr.length就是满了

虽然队列是有 基于链表 和 基于数组两种风格,实际开发中,基于数组的方案是用的更多的。

数组这种方案的优点是什么呢?

1.拥有更高的效率:入队列/出货队列就是简单的head++ tail++ 执行速度更快。这时候就有人想问:“链表,不也就是修改一下引用的指向,时间复杂度也是(1)?为什么说基于数组的执行速度更快?”原因是:链表在进行访问下一个元素的时候,需要多义词间接寻址(先读取引用的值,得到了地址,再根据地址找到对应内存空间)由此处我们可以知道,效率的高与低,运行速度的快和慢都是相对的。

2.对于队列中元素个数的上限是可控的:对于链表版本来说,无限地往里面插入元素,只要你元素够,就可以插入。但是如果你的代码吹按bug了,不小心再入队列,这里就会出现死循环。此时链表版本,不会直接报错,而是把所有的内存都耗尽,导致严重的后果(比如整个程序瘫痪了)但是,如果是数组版本,并且不去自动扩容的话,如果出现类似的问题,后续就能够再入队列的时候及时报错,把问题影响范围缩小。

3.数组版本的队列,内存使用率是更高的:链表版本,由于需要保存额外的next引用,导致内存的利用率更加低。

实现代码:

package Queue;public class MyQueueByArray {//首先创建一个数组private String[] arr = null;//队首private int head = 0;//队尾private  int tail = 0;//队列的元素个数private int size = 0;//来一个构造方法public MyQueueByArray(){arr = new String[1000];}//再来一个给定参数的构造方法public MyQueueByArray(int capacity){arr = new String[capacity];}//1.入队列操作public void offer(String val){//如果队列满了 直接返回if(size == arr.length){return;}//把新的元素,放到tail的位置arr[tail] = val;//更新tail的指向tail++;if(tail == arr.length){tail =0;}//更新tail的指向,其实还有另外一种写法//更推荐上面的写法,而不是这里的 % 的写法//tail=(tail+1)%arr.length;size++;}//2.出队列操作public String poll(){//如果队列为空,直接返回nullif(size ==0){return  null;}//取出队首元素 保存起来 以便接下来返回值String elem = arr[head];head++;//更新head的指向并且进行判断if(head == arr.length){head = 0;}size--;return elem;}//3.查看队首元素public String peek(){if(size ==0){return  null;}return arr[head];}//4.判断队列是否为空public Boolean isEmpty(){return  size ==0;}//5.获取队列长度public int size(){return size;}//测试public static void main(String[] args) {MyQueueByArray myQueueByArray = new MyQueueByArray();myQueueByArray.offer("a");myQueueByArray.offer("b");myQueueByArray.offer("c");myQueueByArray.offer("d");System.out.println(myQueueByArray.peek());System.out.println(myQueueByArray.poll());System.out.println(myQueueByArray.poll());}
}

三、双端队列

双端队列,虽然是叫“队列”,但他也能当作“栈”来使用,addLast搭配removeLast,相当于栈

addFirst 搭配 removeLast 相当于队列

双端队列的实现:

public class Test2 {public static void main(String[] args) {//创建双端队列//Deque<Integer> deque = new ArrayDeque<>();Deque<Integer> deque = new LinkedList<>();//对于Queue提供的各种功能,deque也都是支持的//除此之外,Deque提供了其他的功能}
}

四、有关队列的OJ题

实现思路:

1.准备两个队列A,B

2.入栈:先把A中的所有元素往B里面倒腾(A循环出队列,把出来的元素,入队列到B中)当A中就剩最后一个元素的时候,把这个元素当作栈的元素,删除掉就可以了

当完成一次出栈,所有的元素都被倒腾到B这个队列中了,此时就可以交换A和B的指向,后续如果再需要入栈操作,还是继续往A中添加

4.取栈顶元素:和出栈类似,把A中的元素往B里倒腾,倒腾的过程中,当就剩一个元素的时候,把这个元素的值返回,接下来继续把这个值添加到B中的,然后还是交换A和B

代码段:


// 通过两个队列实现栈.
public class MyStack {private Queue<Integer> A = new LinkedList<>();private Queue<Integer> B = new LinkedList<>();public MyStack() {}private void swap() {Queue<Integer> tmp = A;A = B;B = tmp;}public void push(int x) {// 入栈的时候// 把 x 添加到队列 A 中.A.offer(x);}public int pop() {// 出栈的时候// 判定一下是否为空if (empty()) {// 为空, 直接返回.return 0;}// 把 A 中的元素往 B 里面倒腾. 直到 A 中就剩最后一个元素的时候, 这个元素就可以被删除了.// 循环结束, 就剩一个元素.while (A.size() > 1) {int n = A.poll();B.offer(n);}// 循环结束, 说明 A 中就剩一个元素了. 最后这个元素不能插入到 B 中.int ret = A.poll();// 交换 A 和 B.swap();return ret;}public int top() {if (empty()) {// OJ 题不能抛出异常. 并且也不能修改 返回值类型为 Integer 此时也无法返回 null. 只能返回 0.// 题目本身应该不会有栈为空再 top 的情况.return 0;}// 取栈顶元素, 也是把 A 的元素往 B 里倒腾.while (A.size() > 1) {int n = A.poll();B.offer(n);}// 取出最后一个元素int ret = A.poll();// 把最后一个元素添加到 B 中. (和 pop 相比, 就只是这里多了一行, 别的地方都一样) .B.offer(ret);// 交换 A 和 B.swap();return ret;}public boolean empty() {// 会交换 A 和 B. 所以 B 始终为 空的 . 抓住 A 的空就可以判定整体的 空.return A.isEmpty();}}
/*** Your MyStack object will be instantiated and called as such:* MyStack obj = new MyStack();* obj.push(x);* int param_2 = obj.pop();* int param_3 = obj.top();* boolean param_4 = obj.empty();*/

思路:创建两个栈

1.入队列:把所有B中的元素倒腾到A,往A中入栈

2.出队列:把所有A的元素倒腾给B,从B出栈

3.取队首元素:也是把A的元素倒腾给B,取B的栈顶

4.判定空,确保两个栈都不空,此时整体为空

代码段:

// 使用两个栈, 模拟实现队列.
public class MyQueue {// 创建两个栈// A 用于入队列, B 用于出队列.Stack<Integer> A = new Stack<Integer>();Stack<Integer> B = new Stack<Integer>();public void push(int x) {// 先把 B 中的所有元素倒腾到 A 里, 然后把元素添加到 A 中.while (!B.isEmpty()) {A.push(B.pop());}A.push(x);}public int pop() {// 先把 A 中的所有元素倒腾到 B 里, 然后弹出 B 栈顶元素.while (!A.isEmpty()) {B.push(A.pop());}return B.pop();}public int peek() {// 先把 A 的所有元素倒腾到 B 里, 取 B 的栈顶元素.while (!A.isEmpty()) {B.push(A.pop());}return B.peek();}public boolean empty() {return A.isEmpty() && B.isEmpty();}
}/*** Your MyQueue object will be instantiated and called as such:* MyQueue obj = new MyQueue();* obj.push(x);* int param_2 = obj.pop();* int param_3 = obj.peek();* boolean param_4 = obj.empty();*/

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

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

相关文章

HarmontOS-ArkUI V2状态 !!语法糖 双向绑定

什么是双向绑定 双向绑定指的是在组件间数据的双向绑定。当一个值无论是在父组件还是子组件中改动都会在这两层中都更新界面。 回顾过往的“双向绑定”实现方式 靠@Event装饰回调函数 一般是对于@Param修饰的状态变量。当子组件发生某个动作的时候,调用某个父组件传递过来的…

贪心算法day9(合并区间)

1.合并区间 56. 合并区间 - 力扣&#xff08;LeetCode&#xff09; 对于这种区间问题&#xff0c;我们应该先排序根据排序的结果总结一些规律&#xff0c;进而的得出解决该问题的策略。 class Solution {public static int[][] merge(int[][] intervals) {//第一步进行左端点…

探索加密期权波动率交易的系统化实践——动态对冲工具使用

Trading Volatility – What Are My Options? 在本文中&#xff0c;我们将介绍一些如何交易资产波动性&#xff08;而非资产价格&#xff09;的示例。为了帮助理解&#xff0c;我们将使用 Deribit 上提供的几种不同产品&#xff0c;包括但不限于期权。我们将尽可能消除对标的价…

子函数嵌套的意义——以“颜色排序”为例(Python)

多一层缩进精减参数传递&#xff0c;参数少平铺书代码写更佳。 笔记模板由python脚本于2025-04-16 11:52:53创建&#xff0c;本篇笔记适合喜欢子函数嵌套结构代码形式的coder翻阅。 【学习的细节是欢悦的历程】 博客的核心价值&#xff1a;在于输出思考与经验&#xff0c;而不仅…

【数据结构与算法】LeetCode每日一题

此题跟27.移除数组中的指定值 类似&#xff0c;都是移除且双指针玩法&#xff0c;只不过判断条件发生了变化 此题跟26.删除有序数组中的重复项I 一样&#xff0c;除了fast-1变成了fast-2

c#OleDb连接池管理功能

使用 ConcurrentDictionary 和 ConcurrentBag 来管理数据库连接 using Drv.Utilities; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Data.OleDb; using System.Linq;namespace Drv.AccessClient {/// <summary>…

【Flink运行时架构】核心组件

在Flink的运行架构中&#xff0c;有两大比较重要的组件&#xff1a;作业管理器&#xff08;JobManager&#xff09;和任务管理器&#xff08;TaskManager&#xff09;。 Flink的作业提交与任务处理时的系统如下图所示。 其中&#xff0c;客户端并不是处理系统的一部分&#xff…

牟乃夏《ArcGIS Engine地理信息系统开发教程》学习笔记2

目录 一、ArcGIS Engine概述 1、 定义 2、 核心功能 3、 与ArcObjects&#xff08;AO&#xff09;的关系 二、开发环境搭建 1、 开发工具要求 2、 关键步骤 三、 ArcGIS Engine核心组件 1、 对象模型 2、 类库分类 四、 第一个AE应用程序&#xff08;C#示例&#xf…

端、管、云一体化原生安全架构 告别外挂式防护!

面对数字化转型浪潮&#xff0c;企业网络安全风险日益凸显。数据泄露、黑客勒索等事件频发&#xff0c;合规要求加速推进。尽管企业纷纷部署了防病毒、身份认证、文件加密、入侵防护、流量监控等多种安全系统&#xff0c;但分散且孤立的架构非但没有有效抵御风险&#xff0c;反…

深度学习--深度学习概念、框架以及构造

文章目录 一、深度学习1.什么是深度学习&#xff1f;2.特点3.神经网络构造1&#xff09;.单层神经元2&#xff09;多层神经网络3&#xff09;小结 4.感知器5.多层感知器6.多层感知器&#xff08;偏置节点&#xff09;7.神经网络构造 一、深度学习 1.什么是深度学习&#xff1f…

helm账号密码加密

1、安装工具 sudo apt update sudo apt install gnupg -y wget https://github.com/getsops/sops/releases/download/v3.10.2/sops-v3.10.2.linux.amd64 mv sops-v3.10.2.linux.amd64 /usr/local/bin/sops chmod x /usr/local/bin/sops2、生成加密文件 gpg --full-generate-…

大数据面试问答-HBase/ClickHouse

1. HBase 1.1 概念 HBase是构建在Hadoop HDFS之上的分布式NoSQL数据库&#xff0c;采用列式存储模型&#xff0c;支持海量数据的实时读写和随机访问。适用于高吞吐、低延迟的场景&#xff0c;如实时日志处理、在线交易等。 RowKey&#xff08;行键&#xff09; 定义&#xf…

动态渲染组件

React框架&#xff0c;JSX语法 今天遇到一个好玩的 常规的搜索列表&#xff0c;列表最后一列为操作列&#xff0c;删改查。 眼看着Table 操作列 的配置文件越来越复杂&#xff0c;决定把操作列单独写一个组件&#xff0c;代码瞬间靓仔了些 {title: Operation,dataIndex: oper…

Web APIs阶段

一、Web APIs和JS基础关联性 1.1JS的组成 1.2JS基础阶段以及Web APIs阶段 JS基础阶段&#xff1a;学习的是ECMAScript标准规定的基础语法 Web APIs阶段&#xff1a; Web APIs是W3C组织的标准Web APIs我们主要学习DOM和BOMWeb APIs是JS独有的部分主要学习页面交互功能需要使用…

Doip功能寻址走UDP协议

目前使用 connect()函数的UDP客户端 ,这里接收数据 解析的地方 查看一下。 如果使用 bind()、sendto()、recvfrom() 组合 那么返回值 和发送要在做调整&#xff0c;&#xff0c;根据业务需要后续在调整 其余的 和原来的 逻辑都是一样的&#xff0c;只是协议变了而已。 if serv…

Linux指令的详细介绍

前言&#xff1a;&#x1f33c;&#x1f33c; Linux是一款强大且广泛使用的操作系统&#xff0c;命令行接口&#xff08;CLI&#xff09;是与其交互的核心方式。通过Linux指令&#xff0c;用户可以高效地执行文件管理、系统监控、进程控制等任务。虽然刚接触时可能感到有些复杂…

Elasticsearch使用记录

一、配环境 1.docker版本部署es 8.x系列可以关掉ssl&#xff08;本地测试时&#xff09;&#xff0c;去docker的/usr/share/elasticsearch/config/elasticsearch.yml里面的“xpack.security.enabled:”设置成true就可以 2.window docker部署推荐教程&#xff1a;基于Docker安…

MuJoCo(Multi-Joint Dynamics with Contact)机器人仿真器存在的问题

MuJoCo物理引擎计算接触力的核心思路&#xff0c;是通过数学优化的方式同时满足多个物理约束&#xff0c;而不是简单地为每个碰撞点单独计算作用力。它的工作流程可以理解为几个阶段的紧密配合。首先&#xff0c;仿真器会快速检测所有可能发生接触的物体表面&#xff0c;筛选出…

基础(项目管理工具:JIRA、禅道)

目录 JIRA JIRA介绍 JIRA中的优先级&#xff08;缺陷严重程度&#xff09; JIRA中的解决结果&#xff08;缺陷的解决结果&#xff09; JIRA中的问题状态&#xff08;缺陷的状态&#xff09; 使用JIRA创建缺陷 JIRA的安装&#xff08;Windows&#xff09; JDK22的下载和安…

16.使用豆包将docker-compose的yaml转为k8s的yaml,安装各种无状态服务

文章目录 docker方式httpbinit-toolslinux-commandmyipreference docker-compose安装k8s方式 docker方式 httpbin A simple HTTP Request & Response Service https://httpbin.org/ https://github.com/postmanlabs/httpbin https://github.com/mccutchen/go-httpbin do…