栈和队列深入浅出

目录:
一. 栈的概念及使用
二.栈的相关经典OJ
        三. 队列的概念及使用
        二. 队列的相关经典OJ
一. 栈的概念及使用:
1. 概念: 一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈 顶,另一端称为栈底。栈中的数据元素遵守先进后出的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈; 出栈 栈的 删除操作叫做出栈 压栈和出栈出入数据都在栈顶 如下图:
2 栈的使用
代码:
public static void main(String[] args) {
Stack<Integer> s = new Stack();
s.push(1);
s.push(2);
s.push(3);
s.push(4);
System.out.println(s.size()); // 获取栈中有效元素个数---> 4
System.out.println(s.peek()); // 获取栈顶元素---> 4
s.pop(); // 4出栈,栈中剩余1 2 3,栈顶元素为3
System.out.println(s.pop()); // 3出栈,栈中剩余1 2 栈顶元素为3
if(s.empty()){
System.out.println("栈空");
}else{
System.out.println(s.size());
}
}

3 栈的模拟实现:
1. 注意:这里的peek方法是获得;栈顶元素,当再 push时 后面的元素不会被覆盖 。而
(1)push压栈方法:把元素压入栈中
public class MyStack {public int[] elem;public int usedSize;public MyStack() {this.elem = new int[10];}//压栈public void push(int val) {if (isFull()) {this.elem = Arrays.copyOf(elem,2*elem.length);}this.elem[usedSize++] = val;}

(2)pop出栈方法

public boolean isFull() {return this.usedSize == elem.length;}//判空public boolean isEmpty() {return this.usedSize == 0;}//出栈->获取栈顶元素,并且元素可以被覆盖public int pop() {if (isEmpty()) {throw new ExceptionEmpty("栈是空的!!!");}int val = this.elem[this.usedSize-1];this.usedSize--;//要减减,为后续push可以覆盖元素return val;}

(3) peek方法 获取栈顶元素: 后面 再push时 后面的元素不会被覆盖
 //在不删除元素前提下获取栈顶元素public int peek() {if (isEmpty()) {throw new ExceptionEmpty("栈是空的!!!");}int val = this.elem[this.usedSize-1];//不用要减减return val;}

二.栈的相关经典OJ
1. 最小栈: . - 力扣(LeetCode)
 
我画了超详细的图,帮助理解:
代码:
class MinStack {public Stack<Integer> minStack;public Stack<Integer> stack;public MinStack() {minStack = new Stack<>();stack = new Stack<>();}//入栈public void push(int val) {stack.push(val);if(minStack.empty()) {minStack.push(val);}else {if(val <= minStack.peek()) {minStack.push(val);}}}//出栈public void pop() {if(stack.empty()) {return;}int popVal = stack.pop();//普通栈出栈//最小栈出栈if(popVal == minStack.peek()) {minStack.pop();}}//获取普通栈的栈顶元素public int top() {if(stack.empty()) {return -1;}return stack.peek();}//获取最小栈的栈顶元素public int getMin() {if(minStack.empty()) {return -1;}return minStack.peek();}
}/*** Your MinStack object will be instantiated and called as such:* MinStack obj = new MinStack();* obj.push(val);* obj.pop();* int param_3 = obj.top();* int param_4 = obj.getMin();*/

2.栈的压入、弹出序列栈的压入、弹出序列_牛客题霸_牛客网

理解图:

代码:

//栈的压入、弹出序列public boolean IsPopOrder (int[] pushV, int[] popV) {// write code hereStack<Integer> stack = new Stack<>();int j = 0;for(int i = 0; i < pushV.length; i++) {stack.push(pushV[i]);/*** 这里注意stack.peek() == popV[j],不能写入while循环,不然栈顶元素和popV元素,*              不相等,会一直死循环i不会加加,就没法压入pushV的下一个元素*///注意压栈的同时,和popV[j]比较,不相同借助for循环继续往后压栈while(!stack.empty() && j < pushV.length &&stack.peek() == popV[j]) {stack.pop();j++;}}return stack.empty();}
}

3.逆波兰表达式求值:. - 力扣(LeetCode)

图解:

class Solution {public int evalRPN(String[] tokens) {Stack<Integer> stack = new Stack<>();//遍历字符串for(String str : tokens) {if(!isOperator(str)) {//是字符转为数字,放入栈中int x = Integer.parseInt(str);//字符转为数字stack.push(x);}else {//是操作符,就拿出来两个操作数计算int val2 = stack.pop(); int val1 = stack.pop();switch(str) {case "+":stack.push(val1+val2);break;case "-":stack.push(val1-val2);break;case "*":stack.push(val1*val2);break;case "/":stack.push(val1/val2);break;}}}//最后弹出栈中的元素return stack.pop();}private boolean isOperator(String ch) {if(ch.equals("+") || ch.equals("-") || ch.equals("*") || ch.equals("/")) {return true;}return false;}
}

4. 括号匹配: . - 力扣(LeetCode)
这题画图是关键主要三种情况:要同时,满足栈为空并且 i 遍历完右括号,才是有效括号
代码:
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 {//情况1.栈为空,但是i没有遍历完,右括号多if(Stack.empty()) {return false;}//这里开始比较括号匹不匹配//情况2.(括号顺序不对),刚开始比较第一个括号就不匹配if(Stack.peek() == '[' && ch == ']' || ch == ')'&& Stack.peek() == '(' || ch == '}' && Stack.peek() == '{' ) {Stack.pop();} else {return false;}}} //情况3.栈不为空,虽然i遍历完了,(左括号多)if(!Stack.empty()) {return false;}return true;}
}

三. 队列的概念及使用:
1.  概念 :
队列 只允许在一端进行插入数据操作在另一端进行删除数据操作特殊线性表
队列具有先进先出
入队列进行插入操作的一端称为队尾
 出队列进行删除操作的一端称为队头
2 队列的使用:
Java 中, Queue 是个接口, 底层是通过链表实现
注意:Queue是个接口,在实例化时必须实例化LinkedList的对象因为LinkedList实现 Queu接口。
3. 队列模拟实现:队列的实现,可以使用 顺序结构和链式结构 ,这里我们双链表实现,时间复杂度是O(1)很方便。
offer方法;尾插入队:
public class MyQueue {static class ListNode {public int val;public ListNode next;public ListNode prev;public ListNode(int val) {this.val = val;}}public ListNode first = null;public ListNode last = null;public int usedSize;public void offer (int val) {ListNode node = new ListNode(val);if (isEmpty()) {last = first = node;}else {//尾插last.next = node;node.prev = last;last = last.next;}this.usedSize++;}

poll方法:删除的前提下获取队列队头
 //删除前提下获取队列的队头public int poll() {if (isEmpty()){return -1;}int ret = first.val;first = first.next;//只删剩一个节点时,空没有prev!if(first != null) {first.prev = null;}this.usedSize--;return ret;}

peek方法:不删除的前提下获取队列队头

//不删除前提下获取队列的队头public int peek() {if (isEmpty()){return -1;}return first.val;}public boolean isEmpty() {return this.usedSize == 0;
//       return fast == null;}
}

4.循环队列:
用顺序结构也可以 实现队列 但是普通数组,会比较浪费空间 ,这里我们 让数组循环起来就不会浪费太多空间。这里我们叫它 循环队列。

设计循环队列的oj:. - 力扣(LeetCode)

这里也自己画了理解图:这里我们区分循环队列,是否为非空用了图里说的第三种方法。浪费一个空间
 

代码:

class MyCircularQueue {public int Rear;public int Front;public int[] elem;public MyCircularQueue(int k) {elem = new int[k+1];}//入队列public boolean enQueue(int value) {if(isFull()) {return false;}elem[Rear] = value;Rear = (Rear+1) % elem.length;return true;}//出队列public boolean deQueue() {if(isEmpty()) {return false;}Front = (Front+1) % elem.length;return true;}//不删除获取队头public int Front() {if(isEmpty()) {return -1;}return elem[Front];}//获取队尾public int Rear() {if(isEmpty()) {return -1;}//Rear是插入元素遍历数组的下标int index = ((Rear == 0) ? (elem[elem.length-1]) : (elem[Rear-1]));return index;}public boolean isEmpty() {return Rear == Front;}public boolean isFull() {return (Rear+1) % elem.length == Front;}}/*** Your MyCircularQueue object will be instantiated and called as such:* MyCircularQueue obj = new MyCircularQueue(k);* boolean param_1 = obj.enQueue(value);* boolean param_2 = obj.deQueue();* int param_3 = obj.Front();* int param_4 = obj.Rear();* boolean param_5 = obj.isEmpty();* boolean param_6 = obj.isFull();*/

二. 队列的相关经典OJ:

1. 用队列实现栈 :. - 力扣(LeetCode)

图解:主要就是定义两个队列做到 "先进后出",这里注意入栈和出栈操作,和写peek方法时,定义一个中间变量这些细节,如图:

代码:

class MyStack {Queue<Integer> q1;Queue<Integer> q2;public MyStack() {q1 = new LinkedList<>();q2 = new LinkedList<>();}//模拟入栈public void push(int x) {if(!q1.isEmpty()) {q1.offer(x);}else if(!q2.isEmpty()) {q2.offer(x);}else {//q1或者q2都为空,就任意放一个q1.offer(x);}}//模拟出栈public int pop() {if(empty()) {return -1;}else if(!q1.isEmpty()) {int size = q1.size();for(int i = 0; i < size-1; i++) {q2.offer(q1.poll());}return q1.poll();}else {int size = q2.size();for(int i = 0; i < size-1; i++) {q1.offer(q2.poll());}return q2.poll();}}//模拟获取栈顶元素public int top() {if(empty()) {return -1;}else if(!q1.isEmpty()) {int size = q1.size();//定义一个中间变量,把一个栈的元素经过中间变量//   全部放入另一个栈中,最后返回,最后经过中间变量的元素int val = 0;for(int i = 0; i < size; i++) {val = q1.poll();q2.offer(val);}return val;}else {int size = q2.size();int val = 0;for(int i = 0; i < size; i++) {val = q2.poll();q1.offer(val);}return val;}}public boolean empty() {return q1.isEmpty() && q2.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();*/

2. 用栈实现队列: . - 力扣(LeetCode)
图解:定义两个栈做到 "先进先出",主要就是通过两个栈把栈里的元素反过来
代码:
class MyQueue {public ArrayDeque<Integer> stack1;public ArrayDeque<Integer> stack2;public MyQueue() {stack1 = new ArrayDeque<>();stack2 = new ArrayDeque<>();}//模拟实现入队public void push(int x) {//把与元素全部放入stack1中stack1.push(x);}//模拟实现出队public int pop() {//因为是用栈模拟实现队列,所以判断一下,//如果两个栈为空,那么整个队列就为空if(empty()) {return -1;}//走到这里,stack1 不为空,stack2为空if(stack2.isEmpty()) {//不为空就把stack1全部元素放入stack2,达到元素逆置效果while(!stack1.isEmpty()) {stack2.push(stack1.pop());}}return stack2.pop();}//模拟实现获取队列队头元素(思路和模拟实现出队差不多,只是最后是eek)public int peek() {//因为是用栈模拟实现队列,所以判断一下,//如果两个栈为空,那么整个队列就为空if(empty()) {return -1;}//走到这里,stack1 不为空,stack2为空if(stack2.isEmpty()) {//不为空就把stack1全部元素放入stack2while(!stack1.isEmpty()) {stack2.push(stack1.pop());}}return stack2.peek();}public boolean empty() {return stack1.isEmpty() && stack2.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://xiahunao.cn/news/3247065.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

【前端】ikun-qrcode:极简的二维码生成组件,使用view而非canvas避免层级问题

文章目录 背景ikun-qrcode界面效果如何发布一款自己的插件到uniapp市场。&#xff08;5分钟搞定&#xff09; 背景 之前在uniapp上100行搞定二维码生成&#xff0c; 现在封装为vue组件分享出来&#xff1a; 下载地址&#xff1a; https://ext.dcloud.net.cn/plugin?id19351 …

【C++初阶】C/C++内存管理

【C初阶】C/C内存管理 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;C&#x1f96d; &#x1f33c;文章目录&#x1f33c; 1. C/C内存分布 2. C语言中动态内存管理方式&#xff1a;malloc/calloc/realloc/free 3. C内存管理方式 3…

【Python】AI赋能自动化测试—Applitools Eyes让视觉检查自动化测试更智能、更高效(限时公开)

文章目录 一.视觉回归测试1.什么是视觉回归测试&#xff1f;2.视觉回归测试的必要性3.视觉回归测试是如何工作的&#xff1f;4.常用的视觉回归测试工具有哪些&#xff1f; 二.Applitools Eyes1.是什么2.优缺点3.注册平台账号功能介绍1.界面切换2.单条视觉测试结果解读3.测试视图…

网络开局 与 Underlay网络自动化

由于出口和核心设备 部署在核心机房,地理位置集中,业务复杂,开局通常需要网络工程师进站调测。 因此核心层及核心以上的设备(包含核心层设备,旁挂独立AC设备和出口设备)推荐采用WEB网管开局方式或命令行开局方式。 核心以下的设备(包含汇聚层设备、接入层设备和AP)由于数量众…

发文大刊!Springer旗下1区SCI,收稿量20000+,投稿难度一颗星!

【SciencePub学术】本期&#xff0c;小编给大家推荐的是1本2区计算机综合类SCI&#xff0c;该期刊隶属于Springer出版社&#xff0c;分区逐年上升&#xff0c;现已稳定检索13年&#xff0c;属于Springer旗下的1本口碑优刊。 1 期刊基本信息 【期刊简介】IF&#xff1a;3.0-4.…

【zabbix6监控java-tomcat全流程】

目录 一、监控主机安装zabbix-server1、zabbix的安装2、配置数据库3、为zabbix server配置数据库4、启动服务,web界面安装 二、被监控主机安装tomcat1、安装JDK2、安装tomcat 三、zabbix的服务端安装zabbix-java-gateway四、被监控主机tomcat的配置五、web界面添加主机 一、监控…

python 10的阶乘怎么算

python计算阶乘的方法有很多种&#xff0c;下面给大家介绍三种方法。 第一种&#xff1a;利用functools工具处理 import functools result (lambda k: functools.reduce(int.__mul__, range(1, k 1), 1))(10) print(result) 结果如下&#xff1a; 3628800 第二种&#xff1a…

Tongweb7 日志报错:HttpServletResponse is exceeding the 65535 bytes limit(by lqw)

遇到jsp访问的时候页面加载不全&#xff0c;看tw7日志有如下图信息&#xff1a; 原因&#xff1a; jsp的本质是servlet&#xff0c;编译时会先将他转换成java代码&#xff0c;然后再进行编译。 你的jsp编译成生成的文件太大&#xff0c;导致报错。&#xff08;Java 编译器限制…

【操作系统】定时器(Timer)的实现

这里写目录标题 定时器一、定时器是什么二、标准库中的定时器三、实现定时器 定时器 一、定时器是什么 定时器也是软件开发中的⼀个重要组件.类似于⼀个"闹钟".达到⼀个设定的时间之后,就执行某个指定 好的代码. 定时器是⼀种实际开发中⾮常常用的组件. ⽐如⽹络通…

安全防御---防火墙综合实验3

安全防御—防火墙综合实验3 一、实验拓扑图 二、实验要求 12&#xff0c;对现有网络进行改造升级&#xff0c;将当个防火墙组网改成双机热备的组网形式&#xff0c;做负载分担模式&#xff0c;游客区和DMZ区走FW3&#xff0c;生产区和办公区的流量走FW1 13&#xff0c;办公区…

Jenkins安装nodeJs环境

首先插件市场安装nodeJS插件&#xff0c;我这里已经安装了&#xff0c;没安装的话在 Available plugins 中搜索安装 安装完成后需要下载需要的nodejs版本 新增完成就可以在构建的时候选择当前版本号了

jmeter-beanshell学习11-从文件获取指定数据

参数文件里的参数可能过段时间就不能用了&#xff0c;需要用新的参数。如果有多个交易&#xff0c;读不同的参数文件&#xff0c;但是数据还是一套&#xff0c;就要改多个参数文件。或者只想执行参数文件的某一行数据&#xff0c;又不想调整参数文件顺序。 第一个问题目前想到…

无人驾驶的未来:AI如何重塑我们的出行世界

无人驾驶汽车&#xff0c;作为人工智能&#xff08;AI&#xff09;技术的集大成者&#xff0c;正以前所未有的速度改变着我们的出行方式。从机器学习到计算机视觉&#xff0c;再到人工智能生成内容&#xff08;AIGC&#xff09;&#xff0c;AI技术的每一次进步都在为无人驾驶汽…

C语言 do while循环语句练习 下

猜数字游戏实现 //猜数字游戏 //电脑产生 一个随机数&#xff08;1-100) //猜数字 //猜大了 //猜小了 //直到猜对了&#xff0c;结束 #include <stdlib.h> #include <time.h> void menu() {printf("********************************\n");printf("…

浅谈电商搜索数据指标体系建设

搜索作为电商APP中用户下单的核心场域&#xff0c;具有较高的消费者价值&#xff08;体验&#xff09;、变现价值&#xff08;赚钱&#xff09;、数据沉淀价值&#xff08;研究&#xff09;。因此搭建搜索相关数据指标体系&#xff0c;用于及时监控波动&定位原因就显得至关…

SCI二区TOP|旗鱼优化算法(SFO)原理及实现【免费获取Matlab代码】

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献5.代码获取 1.背景 2023年&#xff0c;S Shadravan受到母亲与孩子之间的人际互动启发&#xff0c;提出了旗鱼优化算法&#xff08;SailFish Optimizer, SFO&#xff09;。 2.算法原理 2.1算法思想 SFO灵感…

Java之split 方法

方法的工作原理 split 方法首先检查字符串中是否存在指定的分隔符。如果存在&#xff0c;它会在每个分隔符处切割字符串&#xff0c;生成一个新的字符串数组。如果字符串中没有指定的分隔符&#xff0c;或者分隔符是非空字符但在字符串中不存在&#xff0c;则 split 方法会返回…

前端简历:项目经历(经验)-外卖送餐类

项目经历-堂食外送点餐 2022年2月-2022年5月 项目描述&#xff1a;该平台提供外送订餐服务&#xff0c;用户可以在手机中轻松地浏览菜品、下单、支付、编辑地址、填写个人信息等&#xff0c;我主要负责首页、订单、我的这3个功能/模块。 技术栈&#xff1a;Amfe-flexibleAxi…

数据包的跨层封装

首先&#xff0c;我们先简单地分析一下数据包的组成结构&#xff1a; 如图 数据包简略地分为以下几层&#xff1a; 二层&#xff1a;封装MAC地址&#xff08;数据链路层&#xff09; 三层&#xff1a;封装IP地址 — 表明源IP和目标IP&#xff0c;主要用于路由器之间的信息转发…

GuLi商城-商品服务-API-品牌管理-JSR303自定义校验注解

自定义注解规则: 可以参考@NotNull注解 package com.nanjing.common.valid;import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target;i…