栈(数据结构系列7)
创始人
2025-05-30 16:33:42
0

前言:

这节中小编带你了解数据结构中的栈结构和队列结构,以及分别自己模拟实现它们,了解他们的使用方法和应用场景。

1.栈

1.1栈的概念

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

栈的形式和入栈、出栈如下图所示:

1.2栈的方法

我们可以直接在idea中看到Stack的一些方法,如下所示:

栈的使用方法
方法功能
Stack()构造一个空的栈
E push(E e)将e入栈,并返回e
E pop()将栈顶元素出栈并返回
E peek()获取栈顶元素
int size()获取栈中有效元素的个数
boolean empty()检测栈是否为空

我们可以通过创建一个栈来直接使用一下这些方法,具体代码如下所示:

package 栈的使用;import java.util.Stack;public class Test1 {public static void main(String[] args) {//创建出一个栈Stack stack = new Stack<>();//压栈操作:pushstack.push(1);stack.push(2);stack.push(3);stack.push(4);//出栈操作:popSystem.out.println(stack.pop());//4System.out.println(stack.pop());//3//查看栈顶元素操作:peekSystem.out.println(stack.peek());//2System.out.println(stack.peek());//2//获取栈中有效元素的个数:size()System.out.println(stack.size());//2//检测是否为空:isEmpty(),此处的isEmpty是继承自Vector的System.out.println(stack.isEmpty());//false}
}

结果如下所示:

1.3栈的模拟实现

下面我们来自己模拟实现一下栈的这些方法吧!

模拟栈代码如下所示:

package 栈的模拟实现;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) {//1.判断栈是否为满if (isFull()) {//进行扩容elem = Arrays.copyOf(elem, 2 * elem.length);}//2.压栈elem[usedSize] = val;usedSize++;}//判断栈是否为满public boolean isFull() {return usedSize == elem.length;}//出栈public int pop() {//1.判断是否为空if (isEmpty()) {throw new EmptyException("栈为空!!!");}//2.出栈return elem[--usedSize];}//查看栈顶元素public int peek() {//1.判断是否为空if (isEmpty()) {throw new EmptyException("栈为空!!!");}//2.出栈return elem[usedSize - 1];}//栈中的有效数字public int size() {return usedSize;}//栈是否为空public boolean isEmpty() {return usedSize == 0;}
}
package 栈的模拟实现;public class EmptyException extends RuntimeException{public EmptyException() {}public EmptyException(String mag) {super(mag);}
}

测试代码如下所示:

package 栈的模拟实现;public class Test {public static void main(String[] args) {//创建一个栈MyStack myStack = new MyStack();//入栈:push()myStack.push(1);myStack.push(2);myStack.push(3);myStack.push(4);//出栈:pop()System.out.println(myStack.pop());//4System.out.println(myStack.pop());//3//查看栈顶元素:peek()System.out.println(myStack.peek());//2System.out.println(myStack.peek());//2//获取栈中有效元素的个数:size()System.out.println(myStack.size());//2//检测是否为空:isEmpty()System.out.println(myStack.isEmpty());//false}
}


结果如下所示:

1.4练习题

1.括号匹配问题。

给出一个仅包含字符'(',')','{','}','['和']',的字符串,判断给出的字符串是否是合法的括号序列
括号必须以正确的顺序关闭,"()"和"()[]{}"都是合法的括号序列,但"(]"和"([)]"不合法。

思想:
1.我们是借助栈来完成的。

2.首先遍历数组,然后再将是左括号的入栈。

3.如果获取到的是右括号,那么就从栈中查看栈顶元素,看是否和右括号匹配,如果匹配就直接出栈,如果不匹配就直接返回false。

4.当发现没有可以入栈的元素的时候就去查看此时的栈是否为空,如果为空那么就说明是匹配成功的,如果不为空那说明就是不匹配的,直接返回false。

代码如下所示:

package 栈的相关练习.括号匹配;import java.util.Scanner;
import java.util.Stack;public class Test1 {public static boolean isValid (String s) {// write code here//1.申请一个栈空间Stack stack = new Stack<>();//2.如果是左括号就入栈for (int i = 0; i < s.length(); i++) {char chl = s.charAt(i);if (chl == '{' || chl == '[' || chl == '(') {stack.push(chl);}else  {//遍历到了右括号,如果栈为空的话那么就说明都是右括号if (stack.isEmpty()) {return false;}//如果栈不为空,遇到了右括号就出栈看是否与之匹配char chr = stack.peek();//拿到左括号if (chl == '}' && chr == '{' || chl == ']' && chr == '[' || chl == ')' && chr == '(') {stack.pop();//将合理的直接弹出栈}else {return false;}}}if (!stack.isEmpty()) {return false;}return true;}public static void main(String[] args) {Scanner scanner = new Scanner(System.in);String i = scanner.next();boolean ret = isValid(i);System.out.println(ret);}
}

结果如下所示:

 

 2.逆波兰表达式求值问题

给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。

请你计算该表达式。返回一个表示表达式值的整数。

注意:

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

思想:

1.首先我们先来解释一下什么是逆波兰表达式。

如果知道的同学可以直接跳过哦,在我们从小接触的数学表达式中我们知道 1 + (2 + 3)* 4 - 5 所表达的含义,以及知道该如何去运算,但是其实还有几种方式可以表达数学式子,有前缀表达式、中缀表达式和后缀表达式,所谓前、中、后都是根据算数运算符的位置来定的,那么对于后缀表达式而言就是算术运算符在数字之后的表达式就叫后缀表达式啦,那么咱们现在所说的这个逆波兰表达式其实就是我现在所说的后缀表达式。

2.那么我们该怎么将一个式子转换成后缀表达式呢?

我们来看下面的这个式子:

1 + (2 + 3)* 4 - 5

我们给这个式子按照运算顺序给他加上括号,就变成下面的这种了:

 然后下一步就是按照每种括号的颜色,将对应的运算符拖到对应颜色的括号外面来:

最后就是删除这些没用的括号,就得到所谓的后缀表达式了也就是逆波兰表达式:

 3.解释了什么是逆波兰表达式之后,那么我们就可以借助我们这节所学的栈来完成运算了。

首先我们先遍历这个表达式,如果遇到数字就压入栈中,如下所示:

如果遇到运算符我们就弹出栈中的两个元素,第一个作为右操作数,第二个作为左操作数,(切记!!!这里的左右操作数不可以放反 )

然后再将所得结果放入栈中:

然后继续重复上述操作,直到栈为空为止,下面我们就来用代码来具体实现一下。 

代码如下所示:

class Solution {public int evalRPN(String[] tokens) {Stack stack = new Stack<>();//1.遍历数组for (int i = 0; i < tokens.length; i++) {String ch = tokens[i];//2.判断是否是运算符if (!isOperation(ch)){//不是运算符就是数字,则将数字入栈stack.push(Integer.parseInt(ch));//需要进行转换}else {//是运算符,弹出两个操作数,,进行运算,然后将运算的结果放入到栈中int left = stack.pop();//左操作数int right = stack.pop();//右操作数int count = 0;switch (ch) {case "+":count = right + left;break;case "-":count = right - left;break;case "*":count = right * left;break;case "/":count= right / left;break;}stack.push(count);}}return stack.pop();}private boolean isOperation(String x) {if (x.equals("+") || x.equals("-") || x.equals("*") || x.equals("/")) {return true;}return false;}
}

3.栈的压入弹出序列问题

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。

思路:

1.我们来借助栈来完成,将给入栈序列和出栈序列分别加上两个指针来进行记录。

2.入栈时,如一个元素i就向后走一步,然后将栈顶元素与出栈序列中j下标的值进行对比如果相同则出栈,同时j向后走一步,如果不相同的话就直接返回false。

下面我们来通过代码来具体实现一下吧!

代码如下所示:

package 出栈入栈次序匹配;import java.util.Stack;public class Test {public static boolean IsPopOrder(int [] pushA, int [] popA) {//1.申请一个栈,用来入pushA中的值Stack stack = new Stack<>();//2.分别对两个序列进行标记int i = 0;int j = 0;while (i < pushA.length) {//入栈stack.push(pushA[i]);//判断是否和j下标的值相同while (j < popA.length && !stack.isEmpty() && stack.peek().equals(popA[j])) {stack.pop();j++;}i++;}return stack.empty();//检查栈是否为空}public static void main(String[] args) {int[] array1 = {1,2,3,4};int[] array2 = {4,3,2,1};boolean ret = IsPopOrder(array1,array2);System.out.println(ret);}
}

结果如下所示:

结束语:

这节博客中小编主要是和大家分享了如何去使用栈和栈的一些练习题,接下来大家一定要多多练习栈相关的习题,小编也会在后期出一些有关栈的一些习题的,大家敬请期待吧!大家继续跟紧小编的步伐一起往下走吧!!!希望对大家有所帮助,想要学习的同学记得关注小编和小编一起学习吧!如果文章中有任何错误也欢迎各位大佬及时为小编指点迷津(在此小编先谢过各位大佬啦!)

相关内容

热门资讯

安卓系统曝光作用原理,揭秘安卓... 你知道吗?最近安卓系统又曝光了一些新动向,这让我这个科技爱好者兴奋不已。今天,就让我带你一探究竟,揭...
安卓盲区监测系统有哪些,安全驾... 你有没有想过,开车的时候,突然一个盲区里的“小家伙”冒了出来,那感觉简直就像是从天而降的惊吓!别担心...
安卓还是苹果系统好用吗,谁更胜... 说到手机系统,安卓和苹果的较量可是从手机诞生之初就开始了。你有没有想过,到底哪个系统更适合你呢?今天...
设置安卓系统的默认相机,功能与... 你有没有发现,每次打开手机拍照,相机界面总是那个老样子?是不是有点审美疲劳了呢?别急,今天就来教你怎...
抖音支持的安卓系统,支持版本全... 你有没有发现,最近抖音可是越来越火了呢?不管是在地铁里、公交车上,还是在家里,总能看到大家刷着抖音,...
安卓系统怎么把文件导出,例如使... 你是不是也和我一样,手机里存了好多宝贝文件,想分享给朋友或者备份到电脑上呢?别急,今天就来教你怎么把...
复印机用安卓系统 你有没有想过,那些默默无闻的复印机竟然也能玩转高科技?没错,就是那个每天帮你打印、复印、扫描的小家伙...
安卓9.0系统怎么安装Busy... 你有没有想过给你的安卓手机来个系统升级,让它焕发新生呢?今天,我就来手把手教你如何安装安卓9.0系统...
安卓12系统安装微信,体验流畅... 你有没有发现,最近你的安卓手机更新到了安卓12系统?是不是有点小激动呢?不过,别急着高兴,因为更新了...
ps安卓系统下载官网,一站式获... 你有没有想过,手机里的安卓系统其实就像是一个神奇的魔法世界?想要探索这个世界的奥秘,第一步就是要找到...
热卖推荐双系统安卓平板,畅享多... 你有没有想过,在这个信息爆炸的时代,拥有一款既能满足工作需求,又能畅享娱乐的平板电脑是多么重要的事情...
换了安卓又想换苹果系统,系统切... 你有没有过这样的经历?手机用着用着,突然就腻了,想要换换口味?这不,我就刚从安卓阵营跳到了苹果的怀抱...
安卓系统比ios容量,iOS系... 你有没有想过,为什么你的安卓手机总是比iOS手机看起来能装下更多的东西呢?这背后其实有着不少门道呢!...
安卓系统如何有两个系统,安卓设... 你有没有想过,你的安卓手机里竟然可以藏着一个秘密世界?没错,就是可以同时拥有两个系统!这听起来是不是...
安卓系统崩溃进不去,深度解析故... 手机突然间罢工了,屏幕上黑漆漆的,安卓系统崩溃了,你心里是不是慌得一批?别急,今天就来给你详细说说安...
苹果系统游戏怎么变安卓,轻松实... 你有没有想过,那些在苹果系统上玩得如痴如醉的游戏,怎么就能在安卓系统上继续畅玩呢?是不是觉得这中间隔...
xp系统读取安卓手机,数据同步... 你有没有想过,你的XP系统竟然能读取安卓手机的数据呢?这听起来是不是有点神奇?别急,今天就来带你一探...
安卓系统用的流量,揭秘手机流量... 你有没有发现,手机里的安卓系统用流量那叫一个“疯狂”?有时候,明明没做什么大动作,流量就“嗖”的一下...
入门安卓机32位系统,轻松驾驭... 你有没有想过,拥有一台入门级的安卓手机,却因为32位系统而头疼不已?别急,今天就来给你详细解析一下这...
安卓系统怎么下对峙2,操作指南... 你有没有想过,在安卓系统上下载一款叫做“对峙2”的游戏会是怎样的体验呢?这款游戏在众多玩家中可是小有...