数据结构----栈的概念、模拟实现、栈的使用、栈的应用、有关栈的算法题

文章目录

  • 1. 栈(Stack) 的概念
  • 2. 栈的模拟实现
  • 3. 栈的使用
  • 4. 栈的应用场景
      • 4.1. 改变元素的序列
      • 4.2. 将递归转化为循环
      • 4.3. 150.逆波兰表达式求值
      • 4.4. 20.括号匹配
      • 4.5 JZ31 栈的压入、弹出序列
      • 4.6 155.最小的栈
  • 5. 概念区分

1. 栈(Stack) 的概念

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

【后进先出LIFO原则】:
在这里插入图片描述

压栈(Push()):栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶
出栈(Pop()):栈的删除操作叫做出栈。出数据在栈顶

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

2. 栈的模拟实现

在这里插入图片描述

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

public class MyStack {int[] array;int size;public MyStack(){array = new int[3];}public int push(int e){ensureCapacity();array[size++] = e;return e;}public int pop(){int e = peek();size--;return e;}public int peek(){if(empty()){throw new RuntimeException("栈为空,无法获取栈顶元素");}return array[size-1];}public int size(){return size;}public boolean empty(){return 0 == size;}private void ensureCapacity(){if(size == array.length){array = Arrays.copyOf(array, size*2);}}
}

3. 栈的使用

方法功能
Stack()构造一个空的栈
E push(E e)将e入栈,并返回e
E pop()将栈顶元素出栈并返回
E peek()获取栈顶元素
int size()获取栈中有效元素个数
boolean empty()检测栈是否为空
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());}
}

4. 栈的应用场景

4.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,C选项中先出的元素为3,说明之前入栈的元素为1、2、3,3出栈之后,出栈顺序一定是2在1之前,2不出来,1不可能先出来。

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

4.2. 将递归转化为循环

比如:逆序打印链表

// 递归方式
void printList(Node head){if(null != head){printList(head.next);System.out.print(head.val + " ");}
}// 循环方式
void printList(Node head){if(null == head){return;}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 + " ");}
}

4.3. 150.逆波兰表达式求值

150.逆波兰表达式求值题目链接
逆波兰表达式介绍

逆波兰表达式又叫做后缀表达式。

  • 表达式一般由操作数(Operand)、运算符(Operator)组成。
  • 算术表达式中,通常把运算符放在两个操作数的中间,这称为中缀表达式(InfixExpression),如A+B。
  • 把运算符写在操作数之前,称为波兰表达式(Polish Expression)或前缀表达式(Prefix Expression),如+AB;
  • 把运算符写在操作数之后,称为逆波兰表达式(Reverse Polish Expression)或后缀表达式(Suffix Expression),如AB+;

假设有一个中缀表达式a+bc-(d+e):
1.首先将这个中缀表达式的所有运算加括号((a+(bc))-(d+e))
2.然后将所有运算符放到括号后面,这样就变成了((a(bc)
)+ (de)+ )-
5. 把所有括号去掉abc*+de+ -,最后得出的结果就是后缀表达式。*

【题目描述】:
给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。
请你计算该表达式。返回一个表示表达式值的整数。

注意:

  • 有效的算符为 ‘+’、‘-’、‘*’ 和 ‘/’ 。
  • 每个操作数(运算对象)都可以是一个整数或者另一个表达式。
  • 两个整数之间的除法总是 向零截断 。
  • 表达式中不含除零运算。
  • 输入是一个根据逆波兰表示法表示的算术表达式。
  • 答案及所有中间计算结果可以用 32 位 整数表示。

【解题】:
1、循环扫描语法单元的项目。
2、如果扫描的项目是操作数,则将其压入操作数堆栈,并扫描下一个项目。
3、如果扫描的项目是一个二元运算符,则对栈的顶上两个操作数执行该运算。
4、将运算结果重新压入堆栈。
5、重复步骤2-4,堆栈中即为结果值。

public int evalRPN(String[] tokens) {Stack<Integer> stack = new Stack<>();for(int i=0;i<tokens.length;i++){String str = tokens[i];if(!isOperation(str)) {int num = Integer.parseInt(str);stack.push(num);}else {int num1 = stack.pop();int num2 = stack.pop();switch(str){case "+":stack.push(num2+num1);break;case "-":stack.push(num2-num1);break;case "*":stack.push(num2*num1);break;case "/":stack.push(num2/num1);break;}}}return stack.pop();}public boolean isOperation(String str) {if (str.equals("+") || str.equals("-") || str.equals("*") || str.equals("/")) {return true;}return false;}

4.4. 20.括号匹配

【题目描述】:
给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:

  • 左括号必须用相同类型的右括号闭合。
  • 左括号必须以正确的顺序闭合。
  • 每个右括号都有一个对应的相同类型的左括号
    在这里插入图片描述
    【解题】:
    只有三种情况下,括号不匹配,只要解决这三种情况,那么剩下的都是括号匹配的情况。
    在这里插入图片描述

解题步骤:
1.如果碰到左括号那么就把它放入栈中;
2.到遇到右括号时,应该和最后一个左括号(在栈中出栈的第一个数据)进行匹配,如果匹配就出栈。
3.最后判断栈中和输入的字符串中的元素是否为空
在这里插入图片描述

    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.empty()) {// 此时,栈为空,但是字符串不为空,右括号多,不符合括号匹配的情况return false;}// 获取最后一个左括号char tmp = stack.peek();// 进行括号匹配if (tmp == '(' && ch == ')' || tmp == '[' && ch == ']' || tmp == '{' && ch == '}') {stack.pop();} else {return false;}}}// 此时,如果栈不为空说明左括号多,栈为空说明左括号和右括号匹配return stack.empty();}

4.5 JZ31 栈的压入、弹出序列

JZ31 栈的压入、弹出序列
【题目描述】:
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。
【解题】:
1.遍历push数组,把元素放到栈中
2.每push一个元素,就和pop数组中的元素比较
3.如果相等j++并且出栈
4.如果不相等,就继续入栈
在这里插入图片描述

public boolean IsPopOrder (int[] pushV, int[] popV) {Stack<Integer> stack = new Stack<>();int j = 0;for (int i = 0; i < pushV.length; i++) {stack.push(pushV[i]);//如果栈中的栈顶的元素和弹出序列数组的元素相同,那么元素出栈并且j++while (!stack.empty() && j < popV.length && stack.peek() == popV[j]) {stack.pop();j++;}}//此时栈的压入顺序数组执行完了,如果循环执行结束,栈中还有元素说明弹出序列和压入序列不对应return stack.empty();}

4.6 155.最小的栈

155.最小的栈
【题目描述】:
设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。实现 MinStack 类:

  • MinStack() 初始化堆栈对象。
  • void push(int val) 将元素val推入堆栈。
  • void pop() 删除堆栈顶部的元素。
  • int top() 获取堆栈顶部的元素。
  • int getMin() 获取堆栈中的最小元素。

【解题】:
方法:辅助栈
在这里插入图片描述
按照如图的思路,我们需要设计一个数据结构,使得每个元素与其相应的最小值保持对应。因此我们可以使用一个辅助栈,用于存储元素对应的最小值。

  1. 当一个元素要入栈时,普通的栈一定要放元素,对于辅助栈如果是空的时,我们要放元素,不为空时我们取当前辅助栈的栈顶存储的最小值,与当前元素比较得出最小值或者相等值,如果该元素较小或者相等,就将该元素插入辅助栈中;
  2. 当一个元素要出栈时,如果与当前辅助栈的栈顶存储的最小值相等,那我们把辅助栈的栈顶元素也一并弹出;不相等时只需要弹出普通栈的值。
  3. 在任意一个时刻,栈内元素的最小值就存储在辅助栈的栈顶元素中。
class MinStack {Stack<Integer> stack;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 peek = minStack.peek();if (val <= peek) {minStack.push(val);}}}public void pop() {//首先弹出普通栈的值int pop = stack.pop();//如果普通栈的值与当前辅助栈的栈顶存储的最小值相等,那我们把辅助栈的栈顶元素也一并弹出if (!minStack.empty()) {if (pop == minStack.peek()) {minStack.pop();}}}public int top() {if (!stack.empty()) {return stack.peek();}return -1;}public int getMin() {if (!minStack.empty()) {return minStack.peek();}return -1;}
}

5. 概念区分

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

  • 栈:栈是一种数据结构,它是一种后进先出(LIFO)的数据结构,只能在栈顶进行插入和删除操作。栈可以用于实现函数调用、表达式求值、内存管理等功能。

  • 虚拟机栈:虚拟机栈是指在计算机中运行的程序中,每个线程都有自己的虚拟机栈,用于存储线程中方法的局部变量、操作数栈、动态链接、返回地址等信息。虚拟机栈的大小可以在程序运行时动态调整。

  • 栈帧:栈帧是指在程序执行过程中,每个方法在虚拟机栈中所占用的一块内存空间,用于存储方法的局部变量、操作数栈、动态链接、返回地址等信息。当一个方法被调用时,会在虚拟机栈中创建一个新的栈帧,当方法执行结束时,栈帧会被销毁。

因此,栈是一种数据结构,虚拟机栈是指程序运行时的内存空间,而栈帧是指虚拟机栈中存储方法信息的一块内存空间。

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

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

相关文章

vue3中如何实现图片的压缩

首先&#xff0c;为什么需要进行图片压缩&#xff1a; 减少页面加载时间&#xff1a;因为图片是页面中常见的资源之一&#xff0c;较大的图片会增加页面的加载时间&#xff0c;影响用户体验&#xff0c;压缩图片可以减小图片的文件大小&#xff0c;提升页面加载速度。节省网络…

2024年【上海市安全员B证】最新解析及上海市安全员B证复审考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 上海市安全员B证最新解析根据新上海市安全员B证考试大纲要求&#xff0c;安全生产模拟考试一点通将上海市安全员B证模拟考试试题进行汇编&#xff0c;组成一套上海市安全员B证全真模拟考试试题&#xff0c;学员可通过…

STC系列单片机定时器

目录 一、定时器的概念 二、单片机程序中的定时器功能代码的实现 &#xff08;1&#xff09;TMOD &#xff08;2&#xff09;AUXR &#xff08;3&#xff09;初始化TH0和TL0 &#xff08;4&#xff09;TR0/EA/ET0三个寄存器 一、定时器的概念 关于定时举个简单的例子&…

Mybatis基础教程及使用细节

本篇主要对Mybatis基础使用进行总结&#xff0c;包括Mybatis的基础操作&#xff0c;使用注解进行增删改查的练习&#xff1b;详细介绍xml映射文件配置过程并且使用xml映射文件进行动态sql语句进行条件查询&#xff1b;为了简化java开发提高效率&#xff0c;介绍一下依赖&#x…

电源芯片并联使用-AMS1117

自记&#xff1a; 电源芯片可不可以并联使用&#xff1a; 1.按照正规大厂Rohm的技术文档介绍&#xff0c;直接并联的两个LDO&#xff0c;只要其输出电压有很小的差异&#xff0c;就会造成电流分配的很大差异。 至于你长期使用没有发现问题&#xff0c;那可能是总电流的余量留…

SketchUp 2023 下载安装教程,保姆级教程,小白也能轻松搞的,附安装包

前言 SketchUp是一套直接面向设计方案创作过程的设计工具&#xff0c;其创作过程不仅能够充分表达设计师的思想而且完全满足与客户即时交流的需要&#xff0c;它使得设计师可以直接在电脑上进行十分直观的构思&#xff0c;是三维建筑设计方案创作的优秀工具。 准备工作 1、W…

玩美移动为花西子海外官网打造AR虚拟试妆决方案

全球领先的增强现实&#xff08;AR&#xff09;及人工智能&#xff08;AI&#xff09;美妆科技领导者及玩美系列APP开发商——玩美移动&#xff08;纽交所代码&#xff1a;PERF&#xff09;于近日宣布携手知名美妆品牌花西子&#xff0c;在其线海外官方网页提供多项彩妆虚拟试妆…

车载以太网:PHY(物理层)介绍

0 工具准备 TJA1101B芯片手册 TJA1101B automotive Ethernet PHY手册 IEEE802.3-2018.pdf 1 车载以太网PHY&#xff08;物理层&#xff09;介绍 常见的普通以太网分为10BASE-2、10/100BASE-TX和1000BASE-T&#xff0c;一般都使用RJ45接口&#xff0c;对于1000BASE-T来说&#…

Open3D 深度图像转点云

目录 一、算法原理1、算法过程2、主要函数3、算法源码二、代码实现三、结果展示1、深度图像2、点云四、测试数据

centos7安装oracle

1 安装虚拟机 设置4G内存&#xff0c;硬盘40G 2 配置网络环境 2.1配置主机名 # vi /etc/hostname 修改为 oracle2.2 配置IP地址 # vi /etc/sysconfig/network-scripts/ifcfg-ens33 修改 BOOTPROTO"static" ONBOOT"yes" IPADDR192.168.109.110 NETMAS…

位运算之妙用:识别独特数字(寻找单身狗)

目录 找单身狗1 图解&#xff1a; 代码如下&#xff1a; 找单身狗2 图解&#xff1a; 代码如下&#xff1a; 寻找单身狗1 从数组中 的1 2 3 4 5 1 2 3 4 中找出没有另一个相同的数与其匹配的数 这个问题的原理是利用异或运算的性质。异或运算&#xff08;XOR&#xff09…

Kafka常见生产问题详解

目录 生产环境常见问题分析 消息零丢失方案 1、生产者发消息到Broker不丢失 2、Broker端保存消息不丢失 3、消费者端防止异步处理丢失消息 消息积压如何处理 如何保证消息顺序 ​问题一、如何保证Producer发到Partition上的消息是有序的 问题二&#xff1a;Partition中…