栈(Stack)

目录

一.栈(Stack)

1.概念

2.栈的使用

3.栈的模拟实现

 二.栈相关习题

1.逆波兰表达式求值

(1)链接

(2)解析

(3)题解

 2.括号匹配

(1)链接

(2)解析

(3)题解

 3.栈的压入弹出序列

(1)链接

(2)解析

(3)题解

4.最小栈

(1)链接

(2)解析

(3)题解


一.栈(Stack)

1.概念

一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出(先进后出

LIFO(Last In First Out)的原则。

压栈(进栈)栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。

出栈栈的删除操作叫做出栈。出数据在栈顶。

栈在我们日常生活中的例子:

2.栈的使用

import java.util.Stack;public class MyStack {public static void main(String[] args) {Stack<Integer> stack = new Stack<>();stack.push(1);stack.push(2);stack.push(3);stack.push(4);stack.push(5);//以上为压栈操作Integer x = stack.peek();System.out.println(x);//获取栈顶元素System.out.println(stack.size());//获取栈内有效元素个数System.out.println(stack.isEmpty());//检查栈是否为空Integer y = stack.pop();System.out.println(y);//出栈操作int z = stack.size();System.out.println(z);}
}

 

注意:

  • 我们在判断栈中是否为空时,可以使用栈这个类中的Empty进行判断,也可以使用Vector类当中的isEmpty进行判断,因为Stack类是继承Vector类的
  • 在以上例子中我们进行出栈操作,获取有效元素个数,获取栈顶元素时,我们既可以通过Integer来进行接收,也可以使用int进行拆箱操作来进行接收

3.栈的模拟实现

栈是一个特殊的顺序表,所以采用链表和数组的方式都可实现,但是,一般采用数组的方式实现

usedSize来表示栈中有效元素个数,入栈一个元素则usedSize++,出栈一个元素则usedSize--,所以此时usedSize有两个含义:

①可以表示当前数据存放的个数

②表示当前存放数据的下标 

说明:usedSize初始值为0,我们往栈里添加元素,将元素添加到下标为0的数组中,此时usedSize为0表示当前存放数据的下标,添加1个元素后,进行usedSize++操作,此时usedSize表示当前数据存放的个数

push()入栈:

  1. 先判断数组是否满了,若满了则进行扩容
  2. 若没满则进行入栈操作,即 将元素按顺序添加到数组中,通过usedSize计数下标来进行添加,添加一个元素,下标就往后走一个,直到满了之后进行扩容

pop()出栈:

  1. 先判断栈中是否有元素,没有则抛出异常
  2. 有元素则进行出栈,我们返回的是栈顶的元素,即usedSize-1的元素即可,
    通过减少 usedSize 的值,我们实际上是在告诉栈:“我们刚刚移除了一个元素,所以现在的栈比刚才小了一个元素

    为什么返回的是useSize-1的值而不是usedSize的值?
    因为在我们进行入栈操作时是先使用的usedSize来表示下标来进行添加元素操作的,添加一个元素usedSize就++,所以此时我们想返回栈顶元素时,栈顶元素的下标就是usedSize-1

    如何进行空间释放?
    因为我们栈中的数据时简单类型,只需要将表示数组中元素个数的usedSize--即可,当下一次进行入栈操作时直接将元素覆盖即可,但如果是引用类型的数据则需要进行置空操作
import java.util.Arrays;public class MyStack {public int[] elem;public int usedSize;public MyStack() {this.elem = new int[10];}public void push(int val){if (isFull()) {//如果满则进行扩容,此处进行两倍扩容elem = Arrays.copyOf(elem,elem.length * 2);}elem[usedSize] = val;//将元素按顺序进行压栈usedSize++;}public boolean isFull() {//判断栈是否满return usedSize == elem.length;}public int pop() {//将栈顶元素出栈,要求弹出栈顶上一个元素的值//如果usedSize为空则无法抛出if (empty()) {throw new RuntimeException("栈中没有元素,不能出栈");}int oldV = elem[usedSize - 1];//存储上一个元素的值usedSize--;return oldV;}public boolean empty() {return usedSize == 0;}public int peek() {if (empty()) {return 0;}return elem[usedSize - 1];}
}

 二.栈相关习题

1.逆波兰表达式求值

(1)链接

逆波兰表达式求值icon-default.png?t=N7T8https://leetcode.cn/problems/evaluate-reverse-polish-notation/description/

(2)解析

解题之前我们先理解什么叫中缀表达式和后缀表达式
 

中缀表达式
该表达式就是我们平常学习中常用的表达式,例如:(3 + 4) * 5


它的特点为:

  • 操作符(如加、减、乘、除等)位于操作数之间。
  • 需要括号来改变默认的运算优先级。

后缀表达式(逆波兰表达式)
例如:3 4 + 5 *(相当于 (3 + 4) * 5,结果是 35)

  • 操作符位于操作数之后。
  • 不需要括号来指明运算优先级,因为操作符的优先级由它们在表达式中的位置决定。

如何将中缀表达式转为后缀表达式呢?

这里我们通过两个例子来进行演示:

  1. 我们将    (3 + 4) * 5    这个中缀表达式转为后缀表达式
    ①我们将这个表达式按照先乘除后加减的规则,将表达式中所有的式子加上括号,即:
            ((3 + 4) * 5)
    ②将运算符移至当前表达式所在括号的外面,即:
            
    ((3 4)+ 5)*
    ③将所有的括号去掉,即
            3  4+  5*
    此时我们就完成了转换
  2.            1 +2*3 +(4*5 +6)*7         再来个更复杂的转换

    对应转换为种植表达式就是:1 +2*3 +(4*5 +6)*7 = 189

总结:

  1. 按照先乘除后加减的规则进行添加括号操作
  2. 将运算符移至当前表达式所在括号的外面
  3. 将所有的括号去掉

后缀表达式是如何存储到栈中并计算呢?

        是操作数就放入栈中,直到遇到运算符,弹出栈顶的第一个元素作为右操作数,第二个作为左操作数,计算出的结果再放入栈中,重复这一操作即可

(3)题解

class Solution {public int evalRPN(String[] tokens) {Stack<Integer> stack = new Stack<>();//遍历数组中的每一个元素for(int i = 0;i < tokens.length;i++) {String tmp = tokens[i];if(!isOperation(tmp)) {//因为我们获取的是数组中的元素,每个元素的类型是字符串,所以我们进行类型转换Integer val = Integer.valueOf(tmp);stack.push(val);}else{Integer val2 = stack.pop();Integer val1 = stack.pop();switch(tmp) {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();}//判断是否是有效的运算符public boolean isOperation(String s) {if(s.equals("+") || s.equals("-") || s.equals("*") || s.equals("/")) {return true;}return false;}
}

 2.括号匹配

(1)链接

括号匹配icon-default.png?t=N7T8https://leetcode.cn/problems/valid-parentheses/description/

(2)解析

分四种情况:

  1. 括号匹配的情况下,栈最终为空且字符串已经遍历完成。(){}
  2. 左括号和右括号不匹配      (]{}
  3. 字符串没有遍历完成,遇到了右括号,但是栈为空。())))
  4. 字符串遍历完成,但是栈当中仍然存在左括号。 (()

只有当获取的字符串为左括号时我们才进行入栈操作,当遇到右括号时我们分为两种情况:①当第一个元素就是右括号,此时栈为空,直接返回false即可②如果右括号不是第一个元素,我们就看当前元素是否与栈顶的元素匹配,若匹配则将栈顶的元素出栈,若不匹配则返回false


当整个循环走完,栈为空时则为true 例:()))),栈内不为空则为false  例:()((

(3)题解

class Solution {public boolean isValid(String s) {Stack<Character> stack = new Stack<>();for(int i = 0;i < s.length();i++) {//1.判断第一个元素是否是左括号char ch = s.charAt(i);if(ch == '(' || ch == '[' || ch == '{' ) {stack.push(ch);} else {//2.遇到了右括号if(stack.empty()) {//如果第一个元素为右括号,此时栈内是空的,直接返回falsereturn false;} else {char chLeft = stack.peek();//获取栈顶元素//判断左右括号是否匹配if(chLeft == '(' && ch == ')' || chLeft == '[' && ch == ']' || chLeft == '{' && ch == '}') {stack.pop();}else {return false;}}}}//当循环走完时,栈内为空则为truereturn stack.empty();}}

 3.栈的压入弹出序列

(1)链接

栈的压入弹出序列icon-default.png?t=N7T8https://www.nowcoder.com/practice/d77d11405cc7470d82554cb392585106?tpId=13&&tqId=11174&rp=1&ru=/activity/oj&qru=/ta/coding-interviews/question-ranking

(2)解析

pushV数组表示压栈后的数组,popV数组表示出栈后的数组可能弹出的顺序

  1. 我们先对pushV数组进行遍历,并将该数组中的元素依次压入栈中,每压一次就与popV数组j下标的元素进行比较,比较之后有两种情况:

    ①若stack中的元素与popV中j下标的元素相同则将栈顶元素进行出栈操作,j++,i++
    (popV数组中必须不能为空,j下标不能超过数组的长度,且只有当栈顶元素与popV数组对应的j下标的元素相等时才会进行出栈操作)

    ②若stack中的元素与popV中j下标的元素不同则i++进行下一次与当前j下标元素的判断(不进入内层循环,直接进行下一次判断)
     
  2. 出栈的过程当中,如果一直是一样的,那么一直出。遇到不一样的。i++继续入栈。
  3. 当循环走完,如果popV数组弹出序列是一致的,那么栈此时应该是空的状态,因此我们只需返回stack.empty()即可

(3)题解

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;//1.遍历pushv数组for(int i = 0; i < pushV.length; i++) {stack.push(pushV[i]);while(j < popV.length && !stack.empty() && stack.peek() == popV[j]){stack.pop();j++;}}return stack.empty();}
}

4.最小栈

(1)链接

最小栈icon-default.png?t=N7T8https://leetcode.cn/problems/min-stack/

(2)解析

存放元素push的过程:

  1. 如果第一次存放元素,普通栈和最小栈都得存放。
  2. 如果不是第一次存放的时候,普通栈肯定得放,但是最小栈
    我们需要和最小栈的栈顶元素比较,是否比最小栈元素小(小于等于)?只有小了才能放

取元素的过程:pop()

  1. 每次pop元素的时候,都需要判断pop的元素是不是和最小栈的栈顶元素一样?一样:最小栈也得pop.

top ==> peek()返回值是普通栈的值


getMin()获取最小栈的栈顶元素

(3)题解

class MinStack {Stack<Integer> stack;Stack<Integer> minStack;public MinStack() {stack = new Stack<>();minStack = new Stack<>();}public void push(int val) {//不论是第几次入栈,stack都要入栈stack.push(val);//最小栈第一次入栈时需要放元素,之后的入栈都需要将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(minStack.peek() == popval) {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();*/

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

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

相关文章

计算机网络——传输层重要协议(TCP、UDP)

一、常见名词解释 IP地址&#xff1a;IP地址主要用于标识网络主机、其他网络设备&#xff08;如路由器&#xff09;的网络地址&#xff0c;即IP地址用于定位主机的网络地址&#xff1b; IP地址是一个32位的二进制数&#xff0c;通常被分割为4个 8位⼆进制数&#xff08;也就是…

构建基于 LlamaIndex 的RAG AI Agent

I built a custom AI agent that thinks and then acts. I didnt invent it though, these agents are known as ReAct Agents and Ill show you how to build one yourself using LlamaIndex in this tutorial. 我构建了一个自定义的AI智能体&#xff0c;它能够思考然后行动。…

京东618 :AI总裁数字人、京东Apple Vision Pro版亮相

2004年6月18日&#xff0c;刚刚转型电商才半年的京东&#xff0c;用最互联网的方式为忠实粉丝打造了一场价格降到“难以置信”的店庆促销活动&#xff0c;这场促销活动还有一个很具有当年网络小说特质的名字——“月黑风高”。 2024年京东618&#xff0c;早已成为一场亿万消费…

泛微开发修炼之旅--20关于Ecology中如何查询正文文件的物理文件,并修改正文中的内容的解决方案

文章链接地址&#xff1a;20关于Ecology中如何查询正文文件的物理文件&#xff0c;并修改正文中的内容的解决方案

Linux系统编程——网络编程

目录 一、对于Socket、TCP/UDP、端口号的认知&#xff1a; 1.1 什么是Socket&#xff1a; 1.2 TCP/UDP对比&#xff1a; 1.3 端口号的作用&#xff1a; 二、字节序 2.1 字节序相关概念&#xff1a; 2.2 为什么会有字节序&#xff1a; 2.3 主机字节序转换成网络字节序函数…

C语言程序设计-10 指针

指针是&#xff23;语言中广泛使用的一种数据类型。运用指针编程是&#xff23;语言最主要的风格之一。利用指针变量可以表示各种数据结构&#xff1b;能很方便地使用数组和字符串&#xff1b;并能象汇编语言一样 处理内存地址&#xff0c;从而编出精练而高效的程序。指针极大地…

C语言 指针——字符数组与字符指针:字符串的输入和输出

目录 逐个字符输入输出字符串 整体输入输出字符串 用scanf输入/输出字符串 用gets输入/输出字符串 用scanf输入/输出字符串 用gets输入/输出字符串 逐个字符输入输出字符串 #define STR_LEN 80 char str[STR_LEN 1 ]; 整体输入输出字符串 用scanf输入/输出字符串 用gets…

【CVPR2021】LoFTR:基于Transformers的无探测器的局部特征匹配方法

LoFTR&#xff1a;基于Transformers的局部检测器 0. 摘要 我们提出了一种新的局部图像特征匹配方法。我们建议先在粗略级别建立像素级密集匹配&#xff0c;然后再在精细级别细化良好匹配&#xff0c;而不是按顺序进行图像特征检测、描述和匹配。与使用成本体积搜索对应关系的密…

oracle12c到19c adg搭建(二)oracle12c数据库软件安装

运行安装程序 不勾选 只安装软件 选择单实例安装 选择语言 企业版 确认目录 产品目录 用户组 开始安装 执行root脚本 [rooto12u19p software]# /u01/app/oraInventory/orainstRoot.sh Changing permissions of /u01/app/oraInventory. Adding read,write permissions for gro…

字节豆包大模型API吞吐、函数调用能力、长上下文能力测试总结

离开模型能力谈API价格都是耍流氓&#xff0c;豆包大模型作为API最便宜的模型之一&#xff0c;最近向个人开发者开放了&#xff0c;花了300元和一些时间对模型的API吞吐、函数调用能力、长上下文能力等进行了深度测试&#xff0c;看看它的能力究竟适合做 AI 应用开发吗&#xf…

【Anaconda】【Windows编程技术】【Python】Anaconda的常用命令及实操

一、Anaconda终端 在安装Anaconda后&#xff0c;电脑上会新增一个Anaconda终端&#xff0c;叫Anaconda Prompt&#xff0c;如下图&#xff1a; 我们选择“打开文件位置”&#xff0c;将快捷方式复制一份到桌面上&#xff0c;这样日后就可以从桌面上方便地访问Anaconda终端了&…

用python实现多文件多文本替换功能

用python实现多文件多文本替换功能 今天修改单位项目代码时由于改变了一个数据结构名称&#xff0c;结果有几十个文件都要修改&#xff0c;一个个改实在太麻烦&#xff0c;又没有搜到比较靠谱的工具软件&#xff0c;于是干脆用python手撸了一个小工具&#xff0c;发现python在…

微服务中的相关概念

Eureka Eureka 是由 Netflix 开发的一个服务发现和注册中心&#xff0c;广泛应用于微服务架构中。Eureka 主要用于管理和协调分布式服务的注册和发现&#xff0c;确保各个服务之间能够方便地找到并通信。它是 Netflix OSS&#xff08;Netflix Open Source Software&#xff09…

C#心跳机制客户端

窗体&#xff08;richTextBox右显示聊天&#xff09; 步骤 点击链接按钮 tcpclient客户端步骤 1创建客户端对象 2连接服务器connect 3创建网络基础流发消息 .write发消息 4 创建网络基础流接消息 .read接消息 5 断开连接…

python库离线安装方法(pyqt5离线安装方法)

在某些情况下&#xff0c;我们的计算机是无法联网的。 网上大部分方法&#xff1a; 这些方法都有个问题&#xff0c;就是库是需要依赖其它库的&#xff0c;你不知道它需要依赖什么库&#xff0c;就是提供了依赖库的列表也麻烦&#xff0c;依赖库也是有对应版本要求的&#xf…

自制调色小工具给图片加滤镜,修改图片红、绿、蓝通道及亮度,修改图片颜色

上篇&#xff1a; 上篇我们给地图添加了锐化、模糊等滤镜&#xff0c;这篇来写一个小工具给图片调色。 调色比锐化等滤镜要简单许多&#xff0c;直接拿到像素值修改即可。不需要用到卷积核。。。(*^▽^*) 核心原理就是图像结构&#xff0c;使用context.getImageData获取图像像…

cad怎么转成pdf文件?方法很简单!

cad怎么转成pdf文件&#xff1f;在数字化时代&#xff0c;CAD图纸的转换与共享已成为日常工作中的常态。无论是建筑设计师、工程师还是学生&#xff0c;都可能遇到需要将CAD文件转换为PDF格式的需求。本文将为您推荐三款高效的CAD转PDF软件&#xff0c;让您轻松实现文件格式的转…

C++ 48 之 继承的基本语法

#include <iostream> #include <string> using namespace std;// 定义一个基类&#xff0c;把公共的部分写在这里&#xff0c;以后让别的类继承即可 class BasePage{ public:void header(){cout << "公共的头部"<< endl;}void footer(){cout…

STM32单片机-BKP和RTC

STM32单片机-BKP和RTC 一、Unix时间戳1.1 时间戳转换 二、BKP(备份寄存器)三、RTC(实时时钟)3.1 RTC工作原理 四、代码部分4.1 BKP备份寄存器4.2 RTC实时时钟 一、Unix时间戳 Unix时间戳定义为从伦敦时间的1970年1月1日0时0分0秒开始所经过的秒数&#xff0c;不考虑闰秒时间戳…

vue3使用echarts简单教程~~概念篇

没写过 写着玩玩 不足的地方还望小伙伴补充~~ 概念篇 文档奉上&#xff1a;数据集 - 概念篇 - 使用手册 - Apache EChartshttps://echarts.apache.org/handbook/zh/concepts/dataset <template><div id"main" style"width: 600px; height: 400px&…