栈(数据结构系列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);}
}

结果如下所示:

结束语:

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

相关内容

热门资讯

安卓系统和oppo系统哪个流畅... 你有没有想过,手机系统哪个更流畅呢?安卓系统和OPPO系统,这两个名字听起来就让人心动。今天,咱们就...
安卓怎么用微软系统,利用微软系... 你是不是也和我一样,对安卓手机上的微软系统充满了好奇?想象那熟悉的Windows界面在你的安卓手机上...
安卓系统如何安装nfc,安卓系... 你有没有想过,用手机刷公交卡、支付账单,是不是比掏出钱包来得酷炫多了?这就得归功于NFC技术啦!今天...
ios系统可以转安卓,跨平台应... 你有没有想过,你的iPhone手机里的那些宝贝应用,能不能搬到安卓手机上继续使用呢?没错,今天就要来...
iOSapp移植到安卓系统,i... 你有没有想过,那些在iOS上让你爱不释手的app,是不是也能在安卓系统上大放异彩呢?今天,就让我带你...
现在安卓随便换系统,探索个性化... 你知道吗?现在安卓手机换系统简直就像换衣服一样简单!没错,就是那种随时随地、随心所欲的感觉。今天,就...
安卓系统安装按钮灰色,探究原因... 最近发现了一个让人头疼的小问题,那就是安卓手机的安装按钮突然变成了灰色,这可真是让人摸不着头脑。你知...
安卓7.1.1操作系统,系统特... 你知道吗?最近我在手机上发现了一个超级酷的新玩意儿——安卓7.1.1操作系统!这可不是什么小打小闹的...
安卓os系统怎么设置,并使用`... 你有没有发现,你的安卓手机有时候就像一个不听话的小孩子,有时候设置起来真是让人头疼呢?别急,今天就来...
安卓降低系统版本5.1,探索安... 你知道吗?最近安卓系统又来了一次大动作,竟然把系统版本给降到了5.1!这可真是让人有点摸不着头脑,不...
解放安卓系统被保护,解放安卓系... 你有没有想过,你的安卓手机其实可以更加自由地呼吸呢?是的,你没听错,我说的就是解放安卓系统被保护的束...
校务帮安卓系统下载,便捷校园生... 你有没有想过,你的手机里装了一个神奇的助手——校务帮安卓系统下载?没错,就是那个能让你轻松管理学校事...
安卓系统没有拼多多,拼多多崛起... 你知道吗?最近我在手机上发现了一个小小的秘密,那就是安卓系统里竟然没有拼多多这个应用!这可真是让我大...
甜城麻将安卓系统,解锁全新麻将... 你有没有听说过那个超级火的甜城麻将安卓系统?没错,就是那个让无数麻将爱好者为之疯狂的软件!今天,就让...
安卓系统卸载的软件,深度揭秘卸... 手机里的软件越来越多,是不是感觉内存不够用了?别急,今天就来教你怎么在安卓系统里卸载那些不再需要的软...
安卓系统推荐好游戏,畅享指尖乐... 手机里的游戏可是咱们休闲娱乐的好伙伴,尤其是安卓系统的用户,选择面那可是相当广呢!今天,就让我来给你...
王者安卓系统怎么卖,揭秘如何轻... 你有没有听说最近王者安卓系统的火爆程度?没错,就是那个让无数玩家沉迷其中的王者荣耀!今天,我就来给你...
安卓开发系统内置证书,基于安卓... 你有没有想过,你的安卓手机里那些神秘的内置证书,它们到底是个啥玩意儿?别急,今天就来给你揭秘这些隐藏...
荣耀安装安卓原生系统,深度体验... 你知道吗?最近荣耀手机界可是掀起了一股热潮,那就是——荣耀安装安卓原生系统!这可不是什么小打小闹,而...
安卓13小米系统,创新功能与流... 你知道吗?最近安卓13系统可谓是风头无两,各大手机厂商纷纷推出自家的新版系统,其中小米的安卓13系统...