栈(数据结构系列7)
创始人
2025-05-30 14:54:04
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);}
}

结果如下所示:

结束语:

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

相关内容

热门资讯

沉浸式体验|绿皮车开进亚布力,... 31日8时,伴随着一声鸣笛,马迭尔文旅投资集团精心策划并开行的Y693次亚布力2日游旅游专列,缓缓驶...
探秘恐龙、赏荷打卡!重庆园博园... 当端午邂逅“六一”,该是一种怎样的体验?重庆园博园邀您开启一场童趣与自然的奇妙之旅! 5月31日—...
弗洛伊德龟兔赛跑算法(弗洛伊德... 弗洛伊德( 罗伯特・弗洛伊德)判圈算法(Floyd Cycle Detection Algorith...
华为MetaERP最佳的免费开... 引言Odoo MES系统是世界排名第一的开源免费Odoo企业管理系统中,车间现场管理相...
web前端-微信小程序开发学习 web前端-微信小程序开发学习1. 小程序的概述2. 小程序的项目结构2.1 小程序项目结构分析2....
C++ Lambda表达式的常... ⭐️我叫忆_恒心,一名喜欢书写博客的在读研究生👨‍🎓。...
【Django 网页Web开发... 目录1. 安装第三方模块2. ORM2.1 自己手动创建数据库2.2 django连接数据库2.3 ...
家常美味轻松做——宫保虾球 家常美味轻松做——宫保虾球 今天给大家带来一道超级美味的家常菜——宫保虾球。这道菜色泽红亮,口感鲜嫩...
实用营养贴士:家常菜这么搭,孩... "你家孩子最近气色真好,是不是换了什么新食谱?"上周家长会,班主任的这句话让我会心一笑。确实,自从调...
炸鱼排有技巧,裹粉前多这一步,... 每次路过快餐店,总被金黄酥脆的炸鱼排勾得走不动道。可自己在家做不是裹粉结块,就是鱼肉又干又柴,咬一口...
解锁这份“粽”味香气,让端午的...   这个端午,山东的粽子“粽”有新意!青绿粽叶裹住晶莹剔透的创意美味,好品风味跃然“粽”上——把子肉...
台山“灰水粽”:侨乡端午节的传... 中新社广东江门5月31日电 题:台山“灰水粽”:侨乡端午节的传统味道 作者 李晓春 郭军 端午节来临...
东营市非遗美食文化嘉年华在大码... 5月31日,2025年东营市非遗美食文化嘉年华暨大码头镇味美虎头鸡•乐购非遗潮活动火热开启,30余项...
粽叶飘香时 温情满油田 五月五 是端阳 插艾叶 挂香囊 采油树下粽飘香 在江苏油田各矿区 综合服务中心所辖食堂 早已支棱起...
吃错鱼=浪费钱!营养师私藏清单... 以下内容为推广 说起青花鱼,想必大家熟悉的吃法,肯定绕不开日料店里的盐烤青花鱼~ 烤得恰如其分、口...
“味源湛江”第二季登陆瑰丽酒店 北京青年报记者5月31日了解到,瑰丽酒店开启“味源湛江”第二季,以更具深度的原产地寻味之旅,在北京的...
原创 “... 一、菌菇类:山珍里的“钾”世珍宝 菌菇家族堪称低调的“钾”中贵族。像滑嫩的口蘑,不仅是鲜味担当,更是...
滨海城市集团强强联手,共建七星... 柬埔寨七星海在多家滨海城市集团的强强联手下,正加速迈向东南亚文旅产业的新高地。集团间资源整合、协同创...
汶川三江旅游攻略大揭秘!绝美风... 这篇攻略将详细介绍汶川三江的旅游信息,涵盖景点特色、最佳旅游时间、交通方式、住宿选择、美食推荐以及游...