【Java数据结构】栈 (Stack)

【本节目标】
1. 栈的概念及使用
2. 相关 OJ

一、概念

  • :一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。
  • 栈中的数据元素遵守后进先出LIFOLast In First Out的原则。
  • 压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶
  • 出栈:栈的删除操作叫做出栈。出数据在栈顶 

栈在现实生活中的例子:

二、栈的使用

 

 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()); // 获取栈中有效元素个数---> 4System.out.println(s.peek()); // 获取栈顶元素---> 4s.pop(); // 4出栈,栈中剩余1 2 3,栈顶元素为3System.out.println(s.pop()); // 3出栈,栈中剩余1 2 栈顶元素为3if(s.empty()){System.out.println("栈空");}else{System.out.println(s.size());}}

三、栈的模拟实现

从上图中可以看到, Stack 继承了 Vector Vector ArrayList 类似,都是动态的顺序表,不同的是 Vector 是线程安全的。

import java.sql.Array;
import java.util.Arrays;public class MyStack {public int[] elem;public int usedSize;public MyStack(int[] elem) {this.elem = new int[10];}public void push(int data){if(ifFull()){grow();}elem[usedSize++]=data;}public boolean ifFull(){return elem.length==usedSize;}private void grow(){elem= Arrays.copyOf(elem,elem.length*2);}public int pop(){if(isEmpty()){throw new  EmptyException("栈为空");}else {int k=usedSize-1;usedSize--;return elem[k];}}private boolean isEmpty(){return usedSize==0;}public int peek(){if(isEmpty()){throw new  EmptyException("栈为空");}else {return elem[usedSize-1];}}
}

四、栈的应用场景

1. 改变元素的序列

1. 若进栈序列为 1,2,3,4 ,进栈过程中可以出栈,则下列不可能的一个出栈序列是()
A: 1,4,3,2                        B: 2,3,4,1                          C: 3,1,4,2                     D: 3,4,2,1
答案:C
2. 一个栈的初始状态为空。现将元素 1 2 3 4 5 A B C D E 依次入栈,然后再依次出栈,则元素出栈的顺序是( )。
A: 12345ABCDE            B: EDCBA54321              C: ABCDE12345           D: 54321EDCBA
答案:B

单链表是否可以实现栈?

答:

  • 顺序表实现的栈可以将插入、删除的时间复杂度达到O(1),
  • 如果采用尾插操作,入栈时间复杂度为O(N),如果有last那么时间复杂度为O(1),但是出栈一定是O(N)
  • 如果采用头插法,入栈时间复杂度为O(1),同时出栈的时间复杂度也是O(1)

结论:

  • 如果采用单链表来实现栈,那么可以采用头插法的形式来入栈和出栈,叫做链式栈
  • 采用双向链表来实现栈是完全ok的,入栈不管是头插还是尾插都可以实现,时间复杂度都可以达到O(1)

2. 将递归转化为循环

比如:逆序打印链表

{Stack<Node> s = new Stack<>();// 将链表中的结点保存在栈中Node cur = head;while(null != cur){s.push(cur);cur = cur.next;}
// 将栈中的元素出栈while(!s.empty()){System.out.print(s.pop().val + " ");}}

3. 括号匹配

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{if(stack.isEmpty()){return false;//不是左括号,但是栈空,右括号多}char ch2=stack.peek();if((ch2=='('&&ch==')')||(ch2=='['&&ch==']')||(ch2=='{'&&ch=='}')){stack.pop();//有括号刚好匹配左括号,出栈}else{return false;//右括号不匹配左括号,错误}}}if(!stack.isEmpty()){return false;//遍历结束但是但是栈不空,左括号多}return true;}
}

4. 逆波兰表达式求值

题目:中缀表达式a+b*c+(d*e+f)*g,其转换成后缀表达式为abc*+de*f+g*+。

将表达式按照运算先后加括号

a+b*c+(d*e+f)*g=a+b*c+(d*e+f)*g

再将每个运算符移出对应的括号外面

a+b*c+(d*e+f)*g)=(abc*+(de*f)+g*+

class Solution {public int evalRPN(String[] tokens) {Stack<Integer> stack=new Stack<>();for(int i=0;i<tokens.length;i++){String ch=tokens[i];if(isOperator(ch)==false){int z=Integer.parseInt(ch);stack.push(z);}else{int y=stack.pop();int x=stack.pop();switch(ch){case"+":stack.push(x+y);break;case"-" :stack.push(x-y);break;case"*" :stack.push(x*y);break;case"/":stack.push(x/y);break;}}}return stack.pop();}private boolean isOperator(String ch){if(ch.equals("+")||ch.equals("-")||ch.equals("*")||ch.equals("/")){return true;}return false;}
}

把字符串变成整形的函数Integer.parseInt() 

5. 出栈入栈次序匹配

顺序遍历pushV,如果栈顶元素和popV当前元素相同,则弹出,不同则将pushV当前元素入栈

import java.util.*;
public class Solution {/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可** * @param pushV int整型一维数组 * @param popV int整型一维数组 * @return bool布尔型*/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]);while(stack.empty()==false&&j<popV.length&&stack.peek()==popV[j]){stack.pop();j++;}}return stack.empty();}
}

6. 最小栈

入栈:

  • 普通栈一定要放
  • 最小栈放的原则:
    • 如果最小栈是空的,则放
    • 如果放的元素小于等于当前栈顶的元素,则放

出栈:判断出栈元素和最小栈栈顶元素关系,相同则最小栈也出去

import java.util.Stack;class MinStack {public Stack<Integer> stack;public  Stack<Integer> minStack;public MinStack() {stack = new Stack<>();minStack = new Stack<>();}public void push(int val) {stack.push(val);if(minStack.empty()) {minStack.push(val);}else {int peekVal = minStack.peek();if(val <= peekVal) {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();}
}

五、 概念区分

栈、虚拟机栈、栈帧有什么区别呢?
  • 栈:是一种数据结构
  • 虚拟机栈:是jvm中的一块内存
  • 栈帧:运行一个方法、一个函数时,给它开辟的内存

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

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

相关文章

【2024】前端学习笔记11-网页布局-弹性布局flex

学习笔记 网页布局弹性布局&#xff1a;flex案例&#xff1a;flex布局案例 网页布局 在页面布局中&#xff0c;display属性用于设置一个元素的显示方式。它可以指定元素是作为块级元素、内联元素还是充当表格元素显示。 display的常见属性值&#xff1a; block&#xff1a;将…

k8s 中微服务之 MetailLB 搭配 ingress-nginx 实现七层负载

目录 1 MetailLB 搭建 1.1 MetalLB 的作用和原理 1.2 MetalLB功能 1.3 部署 MetalLB 1.3.1 创建deployment控制器和创建一个服务 1.3.2 下载MealLB清单文件 1.3.3 使用 docker 对镜像进行拉取 1.3.4 将镜像上传至私人仓库 1.3.5 将官方仓库地址修改为本地私人地址 1.3.6 运行清…

ensp回顾--聚合链路技术简介与详细案例(构建基于交换机到交换机的聚合链路)

文章目录 什么是聚合链路&#xff1f;聚合链路的工作原理聚合链路的优势使用场景 案例ensp版本图例pc的ip地址具体步骤连通性测试 在现代网络中&#xff0c;聚合链路&#xff08;Link Aggregation&#xff09;是一种常见的技术&#xff0c;用于提高网络连接的带宽和可靠性。本文…

RNN经典案例——构建人名分类器

RNN经典案例——人名分类器 一、数据处理1.1 去掉语言中的重音标记1.2 读取数据1.3 构建人名类别与人名对应关系字典1.4 将人名转换为对应的onehot张量 二、构建RNN模型2.1 构建传统RNN模型2.2 构建LSTM模型2.3 构建GRU模型 三、构建训练函数并进行训练3.1 从输出结果中获得指定…

【可答疑】基于51单片机的智能台灯(含仿真、代码、报告、演示视频等)

✨哈喽大家好&#xff0c;这里是每天一杯冰美式oh&#xff0c;985电子本硕&#xff0c;大厂嵌入式在职0.3年&#xff0c;业余时间做做单片机小项目&#xff0c;有需要也可以提供就业指导&#xff08;免费&#xff09;~ &#x1f431;‍&#x1f409;这是51单片机毕业设计100篇…

数据分析-28-交互式数据分析EDA工具和低代码数据科学工具

文章目录 1 数据分析的七步指南1.1 第一步:问题定义和数据采集1.2 第二步:数据清洗和预处理1.3 第三步:数据探索和分析1.4 第四步:模型建立和分析1.5 第五步:数据可视化1.6 第六步:结果解释和报告1.7 第七步:部署和维护1.8 基础的数据分析库1.9 低代码数据科学工具2 EDA…

STM32 通用定时器

一、概述 STM32内部集成了多个定时/计数器&#xff0c;根据型号不同&#xff0c;STM32系列芯片最多包含8个定时/计数器。其中&#xff0c;TIM6、TIM7为基本定时器&#xff0c;TIM2~TIM5为通用定时器&#xff0c;TIM1、TIM8为高级控制定时器。 1.定时器的类型 基本定时器通用定…

实战案例:结合大模型与爬虫技术实现12306智能查票系统

大语言模型&#xff0c;例如 GPT-4&#xff0c;拥有强大的知识储备和语言理解能力&#xff0c;能够进行流畅的对话、创作精彩的故事&#xff0c;甚至编写代码。然而&#xff0c;它们也面临着一些难以克服的困境&#xff0c;就像一个空有知识却无法行动的巨人 信息滞后&#xf…

Linux 之 安装软件、GCC编译器、Linux 操作系统基础

安装软件、GCC编译器、Linux 操作系统基础 学习任务&#xff1a; 安装 Vmware虚拟机、掌握Ubuntu 系统的使用认识 Ubuntu 操作系统的终端和 Shell掌握软件安装、文件系统、掌握磁盘管理与解压缩掌握 VIM 编辑器、Makefile 基本语法熟悉 Linux 常见指令操作 安装好开发软件&…

[Go语言快速上手]初识Go语言

目录 一、什么是Go语言 二、第一段Go程序 1、Go语言结构 注意 2、Go基础语法 关键字 运算符优先级 三、Go语言数据类型 示例 小结 一、什么是Go语言 Go语言&#xff0c;通常被称为Golang&#xff0c;是一种静态类型、编译型的计算机编程语言。它由Google的Robert Gr…

用HTML5+CSS+JavaScript庆祝国庆

用HTML5CSSJavaScript庆祝国庆 中华人民共和国的国庆日是每年的10月1日。 1949年10月1日&#xff0c;中华人民共和国中央人民政府成立&#xff0c;在首都北京天安门广场举行了开国大典&#xff0c;中央人民政府主席毛泽东庄严宣告中华人民共和国成立&#xff0c;并亲手升起了…

Vue3 中Ref的最佳实践

在vue3中如果我们需要获取一个响应式的变量&#xff0c;可以使用ref来定义一个变量。 const name ref( "" );name.value "test" 定义好后&#xff0c;就可以实现修改状态&#xff0c;更新UI的效果了。 在这个基础上&#xff0c;本文主要讨论跨组件时如何…

Discord:报错:A fatal Javascript error occured(解决办法)

按 Windows 键 R 并输入 %appdata% 选择 discord 文件夹并将其删除。 再次按 Windows 键 R 并输入 %LocalAppData% 选择 discord 文件夹并再次将其删除。 附加&#xff1a; 如果还不行&#xff0c;就通过官网下载吧&#xff0c;这个问题通过epic下载可能会有

Python并发编程挑战与解决方案

Python并发编程挑战与解决方案 并发编程是现代软件开发中的一项核心能力&#xff0c;它允许多个任务同时运行&#xff0c;提高程序的性能和响应速度。Python因其易用性和灵活性而广受欢迎&#xff0c;但其全局解释器锁&#xff08;GIL&#xff09;以及其他特性给并发编程带来了…

Docker面试-24年

1、Docker 是什么&#xff1f; Docker一个开源的应用容器引擎&#xff0c;是实现容器技术的一种工具&#xff0c;让开发者可以打包他们的应用以及环境到一个镜像中&#xff0c;可以快速的发布到任何流行的操作系统上。 2、Docker的三大核心是什么? 镜像&#xff1a;Docker的…

网络威胁情报技术的进步

网络威胁形势不断演变&#xff0c;必然导致防御者和攻击者之间持续展开军备竞赛。幸运的是&#xff0c;网络威胁情报 (CTI) 技术的进步为安全专业人员提供了强大的工具&#xff0c;使他们能够保持领先地位。 本指南深入探讨了 CTI 的最新进展&#xff0c;让您了解这些技术如何…

【学习笔记】手写一个简单的 Spring MVC

目录 一、什么是Spring MVC &#xff1f; Spring 和 Spring MVC 的区别&#xff1f; Spring MVC 的运行流程&#xff1f; 二、实现步骤 1. DispatcherServlet 1. 创建一个中央分发器 拦截所有请求 测试 2. 接管 IOC 容器 1. 创建配置文件 2. 修改 web.xml 配置文件 …

1分钟搞懂K8S中的NodeSelector

文章目录 NodeSelector是什么&#xff1f;为什么使用NodeSelector&#xff1f;怎么用NodeSelector&#xff1f;POD配置示例yaml配置示例 如何知道K8S上面有哪些节点&#xff0c;每个节点都有什么信息呢&#xff1f;1. 使用kubectl命令行工具查看所有节点及其标签2. 使用kubectl…

算法【Java】—— 二叉树的深搜

深搜 深搜简单来说就是一直递归到底&#xff0c;然后返回&#xff0c;以二叉树为例&#xff0c;就是从根节点出发一直搜索到叶子节点&#xff0c;然后想上返回。 这里简单说明一下&#xff1a;深搜的英文缩写是 dfs&#xff0c;下面定义深搜函数名我直接命名为 dfs 实战演练 …

内存占用估算方法

优质博文&#xff1a;IT-BLOG-CN 通过掌握每种数据类型的大小&#xff0c;就可以更准确地预测对象和数据的内存消耗。 一、基础数据类型 Java基础数据类型结构&#xff0c;在64位系统开启指针压缩情况下的内存占用字节数&#xff1a; booleanbytecharshortintlongfloatdoub…