数据结构 - 栈 (逆波兰计算器)(栈的三种表达式)(前缀、中缀和后缀表达式,后缀也叫逆波兰表达式)(中缀表达式转后缀表达式实现步骤及完整代码)

栈的三种表达式:前缀、中缀和后缀表达式,后缀也叫逆波兰表达式

前缀(波兰表达式)

在这里插入图片描述

中缀(对人来讲很好理解,对于计算机来讲就方便了,一般会把中缀表达式转换成后缀表达式)

在这里插入图片描述

后缀(逆波兰表达式)

在这里插入图片描述

计算过程

在这里插入图片描述

例字

在这里插入图片描述

这里就用java自带的栈了Stack(多位数也可以)(自己写个栈也可以,这里为了方便)

(这里输入的是后缀表达式,中缀转后缀往下看)

package stack;import java.util.ArrayList;
import java.util.List;
import java.util.Stack;public class PolandNotation {public static void main(String []args){//先定义一个逆波兰表达式//(3+4)*5-6 => 3 4 + 5 * 6 -//为了方便数字和符号使用空格隔开String suffixExpression = "3 4 + 5 * 6 -";//思路// 1.先将3 4 + 5 * 6 -放入ArrayList中// 2.将ArrayList 传递给一个方法,遍历ArrayList 配合栈完成计算List<String> list = getListString(suffixExpression);int res = calculate(list);System.out.println(res);}//将表达式,依次将输入和运算符 方法欧ArrayList中public static List<String> getListString(String suffixExperssion){//分割String[] split = suffixExperssion.split(" ");ArrayList<String> list = new ArrayList<>();for (String ele : split){list.add(ele);}return list;}public static int calculate(List<String> ls){//创建栈,只需要一个栈Stack<String> stack = new Stack<>();//遍历for (String item : ls){//使用正则取出数if (item.matches("\\d+")){ //匹配多位数stack.push(item);}else {//pop出两个数运算int num2 = Integer.parseInt(stack.pop());int num1 = Integer.parseInt(stack.pop());int res = 0;if (item.equals("+")){res = num1+num2;}else if (item.equals("-")){res = num1 - num2;}else if (item.equals("*")){res = num1 * num2;}else if (item.equals("/")){res = num1 / num2;}else {throw new RuntimeException("运算符有误");}//res 入栈stack.push(res + "");}}//最后留在stack中的数是结果return Integer.parseInt(stack.pop());}
}

中缀表达式 转 后缀表达式

1)操作步骤:

在这里插入图片描述在这里插入图片描述

2)例

在这里插入图片描述

代码几乎每行都有注释,根据思路一步一步分析来自己实现一下。

1)中缀转后缀代码

public static List<String> parseSuffixExpressionList(List<String> ls){//定义两个栈Stack<String> s1 = new Stack<>(); //符号栈//说明:因为S2栈,并没有用到pop,而且后面还需要逆序说出,比较麻烦//Stack<String> stack2 = new Stack<>(); //中间结果的栈//这里就用List来代替ArrayList<String> s2 = new ArrayList<String>();//遍历lsfor (String item : ls){//如果是数就入栈if (item.matches("\\d+")){s2.add(item);} else if (item.equals("(")){s1.push(item);} else if (item.equals(")")){while (!s1.peek().equals("(")){//s1内容加入s2s2.add(s1.pop());}s1.pop(); // 将(弹出s1栈} else {//当s1栈顶的运算符的优先级 大于等于 item运算符的优先级 ,将s1栈顶的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈顶运算符相比较;//这里缺少一个比较优先级高低的方法while (s1.size() != 0 && Operation.getValue(s1.peek()) >= Operation.getValue(item)){s2.add(s1.pop());}//最后还需要将item压入栈中s1.push(item);}}//将s1中剩下的运算符依次弹出加入s2中while (s1.size() != 0){s2.add(s1.pop());}//因为存放了List里,直接顺序输入就是对应的逆波兰表达式return s2;}

2)判断符号优先级

//编写一个类,Operation 可以返回一个运算符 对应的优先级
class Operation{private static int ADD = 1;private static int SUB = 1;private static int MUL = 2;private static int DIV = 2;//写一个方法,返回对应优先级数字public static int getValue(String operation){int result = 0;switch (operation) {case "+":result = ADD;break;case "-":result = SUB;break;case "*":result = MUL;break;case "/":result = DIV;break;default:result = 0;//这里是栈中是(,那么结果设成0,不管什么运算符都存进来break;}return result;}
}

完整代码(以及上面的运算)

package stack;import java.util.ArrayList;
import java.util.List;
import java.util.Stack;public class PolandNotation {public static void main(String []args){//完成中缀表达式转成后缀表达式//说明// 1.因为直接对str 进行操作,不方便, 因此先将"1+((2+3)*4)-5" =》中缀表达式转成对应的List// 2.即"1+((2+3)*4)-5" =》 ArrayList[1,+,(,(,2,+,3,*,4,),-,5]String expression = "1+((2+3)*4)-5";//中缀表达式转成ListList<String> list = toInfixExpressionList(expression);System.out.println("中缀表达式:" + list);//中缀表达式:[1, +, (, (, 2, +, 3, ), *, 4, ), -, 5]//把ArrayList[1,+,(,(,2,+,3,*,4,),-,5] =》"1 2 3 + 4 × + 5 –"List<String> parseSuffixExpressionList = parseSuffixExpressionList(list);System.out.println("后缀表达式:" + parseSuffixExpressionList);//后缀表达式:[1, 2, 3, +, 4, *, +, 5, -]//计算转换后的后缀表达式int calculate = calculate(parseSuffixExpressionList);System.out.println("后缀表达式计算结果:" + calculate);/*//先定义一个逆波兰表达式//(3+4)*5-6 => 3 4 + 5 * 6 -//测试(30+4)*5-6//为了方便数字和符号使用空格隔开String suffixExpression = "30 4 + 5 * 6 -";//思路// 1.先将3 4 + 5 * 6 -放入ArrayList中// 2.将ArrayList 传递给一个方法,遍历ArrayList 配合栈完成计算List<String> list = getListString(suffixExpression);int res = calculate(list);System.out.println(res);*/}//方法:将得到的中缀表达式转换成后缀表达式具体步骤如下://        //初始化两个栈:运算符栈s1和储存中间结果的栈s2;//        //从左至右扫描中缀表达式;//        //遇到操作数时,将其压s2;//        //遇到运算符时,比较其与s1栈顶运算符的优先级://        //如果s1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;//        //否则,若优先级比栈顶运算符的高,也将运算符压入s1;//        //否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈顶运算符相比较;//        //遇到括号时:(1) 如果是左括号“(”,则直接压入s1(2) 如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃//        //重复步骤2至5,直到表达式的最右边//        //将s1中剩余的运算符依次弹出并压入s2//        //依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式public static List<String> parseSuffixExpressionList(List<String> ls){//定义两个栈Stack<String> s1 = new Stack<>(); //符号栈//说明:因为S2栈,并没有用到pop,而且后面还需要逆序说出,比较麻烦//Stack<String> stack2 = new Stack<>(); //中间结果的栈//这里就用List来代替ArrayList<String> s2 = new ArrayList<String>();//遍历lsfor (String item : ls){//如果是数就入栈if (item.matches("\\d+")){s2.add(item);} else if (item.equals("(")){s1.push(item);} else if (item.equals(")")){while (!s1.peek().equals("(")){//s1内容加入s2s2.add(s1.pop());}s1.pop(); // 将(弹出s1栈} else {//当s1栈顶的运算符的优先级 大于等于 item运算符的优先级 ,将s1栈顶的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈顶运算符相比较;//这里缺少一个比较优先级高低的方法while (s1.size() != 0 && Operation.getValue(s1.peek()) >= Operation.getValue(item)){s2.add(s1.pop());}//最后还需要将item压入栈中s1.push(item);}}//将s1中剩下的运算符依次弹出加入s2中while (s1.size() != 0){s2.add(s1.pop());}//因为存放了List里,直接顺序输入就是对应的逆波兰表达式return s2;}//方法:将字符串中缀表达式转为Listpublic static List<String> toInfixExpressionList(String s){//电影以一个List,存放中缀表达式ArrayList<String> list = new ArrayList<>();int i = 0;//相当于一个指针,用于遍历字符串String str;//对多位数进行拼接char c; //每遍历到一个字符就放到c中do {//如果c是一个非数字,我们就需要加入到list里if ((c = s.charAt(i)) < 48 || (c= s.charAt(i)) >57){list.add("" + c);i++; //i后移} else { // 如果是一个数,需要考虑多位数str = ""; //str清空while (i < s.length() && (c=s.charAt(i)) >= 48 && (c=s.charAt(i)) <= 57){str += c; //拼接i++;}list.add(str);}}while(i < s.length());return list;}//将表达式,依次将输入和运算符 方法欧ArrayList中public static List<String> getListString(String suffixExperssion){//分割String[] split = suffixExperssion.split(" ");ArrayList<String> list = new ArrayList<>();for (String ele : split){list.add(ele);}return list;}public static int calculate(List<String> ls){//创建栈,只需要一个栈Stack<String> stack = new Stack<>();//遍历for (String item : ls){//使用正则取出数if (item.matches("\\d+")){ //匹配多位数stack.push(item);}else {//pop出两个数运算int num2 = Integer.parseInt(stack.pop());int num1 = Integer.parseInt(stack.pop());int res = 0;if (item.equals("+")){res = num1+num2;}else if (item.equals("-")){res = num1 - num2;}else if (item.equals("*")){res = num1 * num2;}else if (item.equals("/")){res = num1 / num2;}else {throw new RuntimeException("运算符有误");}//res 入栈stack.push(res + "");}}//最后留在stack中的数是结果return Integer.parseInt(stack.pop());}
}//编写一个类,Operation 可以返回一个运算符 对应的优先级
class Operation{private static int ADD = 1;private static int SUB = 1;private static int MUL = 2;private static int DIV = 2;//写一个方法,返回对应优先级数字public static int getValue(String operation){int result = 0;switch (operation) {case "+":result = ADD;break;case "-":result = SUB;break;case "*":result = MUL;break;case "/":result = DIV;break;default:result = 0;break;}return result;}
}
结果:
中缀表达式:[1, +, (, (, 2, +, 3, ), *, 4, ), -, 5]
后缀表达式:[1, 2, 3, +, 4, *, +, 5, -]
后缀表达式计算结果:16

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

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

相关文章

数据结构与算法 - 递归回溯(迷宫问题)

递归的概念 简单说就是方法自己调用自己&#xff0c;每次调用时传入不同的变量&#xff0c;递归有助于编程者解决复杂的问题&#xff0c;同时可以让代码简介 递归的调用机制 递归能解决什么问题 递归需要遵守的重要规则 下面用代码来实现一个迷宫问题 主要代码&#xff08;这…

【转】Web Reference和Service Reference的区别

今天因为项目需要使用服务引用&#xff0c;就按之前的经验添加上了&#xff0c;步骤如下&#xff1a; 项目根目录——引用——右键——添加服务引用——高级——添加Web引用——输入接口的URL地址——回车&#xff08;下方出现的就是接口的定义的方法&#xff09;——修改Web引…

数据结构 - 递归 回溯算法(八皇后问题)

游戏地址自己写完了可以根据结果去测试一下。 算法分析 八皇后问题算法思路分析 1&#xff09;第一个皇后先放第一行第一列 2&#xff09;第二个皇后放在第二行第一列、然后判断是否OK&#xff0c; 如果不OK&#xff0c;继续放在.第二列、第三列、依次把所有列都放完&#x…

算法 - 排序算法 的时间复杂度计算

简介 度量一个程序(算法)执行时间的两种方法 1&#xff09;事后统计的方法这种方法可行, 但是有两个问题&#xff1a;一是要想对设计的算法的运行性能进行评测&#xff0c;需要实际运行该程序&#xff1b;二是所得时间的统计量依赖于计算机的硬件、软件等环境因素, 这种方式&a…

【转】Magento2目录结构

目录结构 可以看到,M2的目录挺多的。 我们依次来讲解下, 我这里截取的是github里的源代码,核心代码跟composer和官网下载的源码包的存放路径不一样。 如果是github下载的&#xff0c;那么m2的核心源代码就在app/code/Magento里。 如果是composer安装或者官网下载的源码包&#…

算法 - 排序算法 (算法学习)(冒泡、选择、插入、希尔、快排、归并)

1&#xff09;冒泡排序 1.1 图解演示 2&#xff09;选择排序 import java.text.SimpleDateFormat; import java.util.Date;/*** 选择排序*/ public class chooseSort {public static void selectSort(int[] arr){for (int i 0; i < arr.length; i) {int minIndex i;int m…

【转】1.4 Magento2语法讲解

M2不是一个标准的MVC架构。 这是m2的app/code/Magento/Catalog插件代码。 可以看到&#xff0c;它有Controller,也有Model,也有view. 奇怪的是,在Controller找不到调用模版的代码。 这是因为我们之前讲过,m2的页面都是用xml写的&#xff0c;xml里是由若干个block组成的。block里…

【转】1.5 运行原理剖析

我们不讲底层架构,核心原理,太枯燥&#xff0c;也记不住&#xff0c;没必要。 毕竟不是人人都要当架构师。 我们从M2的模式说起。 理解了他的模式,就知道了他的原理。 M2有3种模式, 默认模式(default)开发模式(developer)生产模式(production) 默认模式 安装完成后&#xf…

SparkStreaming简介 - 与第一个Spark实时计算程序,使用netcat来写数据 - wordcount

官方文档 Spark Streaming 火花流是spark API的扩展&#xff0c;它支持可伸缩、高吞吐量、容错的实时数据流处理。 数据可以从多种来源(如Kafka、Flume、Kinesis或tcp套接字)中摄取&#xff0c;并且可以使用用高级函数表示的复杂算法进行处理&#xff0c;例如map, reduce, jo…

【转】老邹说Magento的前世今生

文章目录[隐藏] Magento Commerce的历史Magento 2版本历史Magento电子商务的特点和功能Magento市场Magento认证Magento事件为什么Magento统治电子商务领域 想要深入了解magento&#xff0c;我们有必要回顾一下Magento的前世今生&#xff0c;看它是如何一步步成长起来的。 为什…

【转】Magento2 安装系列一 虚拟机、CentOS7 安装

前言 最近打算在Windows10安装最新的magento2.3&#xff0c;由于mg2.3对Windows支持不太友好&#xff0c;所以就打算在Windows10安装虚拟机&#xff0c;虚拟机安装CentOS7版本的Linux&#xff0c;Linux安装Lnmp环境&#xff0c;最终安装Magento2.3.虚拟机选择与安装 我这边打算…

SparkStreaming -Kafka数据源

SparkStreaming处理kafka作为数据源 所以我们要创建的是kafka的Dstream&#xff0c;那么就要使用到KafkaUtils下的createStream&#xff0c;先来看一下ctrl点进去查看&#xff0c;然后来写参数 package date_10_16_SparkStreamingimport org.apache.spark.SparkConf import or…

SparkStreaming - 无状态与有状态 updataStateByKey

无状态与有状态 简单来说&#xff0c;无状态就是每个采集周期分别采集&#xff0c;并不会把前面的采集周期的数据一起计算 有状态就是&#xff1a;把前面采集周期的也算进来&#xff0c; 比如wordcount&#xff0c;无状态统计的就是每个采集周期内的个数&#xff0c;有状态的…

flink(一个流处理,一个批处理)

流处理&#xff0c;这里用netcat来完成 package com.smalltiger.flinkWCimport org.apache.flink.api.java.utils.ParameterTool import org.apache.flink.streaming.api.scala._/*** Created by smalltiger on 2019/11/6.* flink基于流处理的一个WordCount统计*/ object Stre…

volatile学习(可见性,不保证原子性,禁止指令重排(双端检索机制))

volatile是java虚拟机提供的轻量级的同步机制&#xff1a; 1.保证可见性&#xff1a;线程之间可见性(及时通知) 2.不保证原子性 3.禁止指令重排 先了解一下jvm同步 由于JVM运行程序的实体是线程&#xff0c;而每个线程创建时JVM都会为其创建一个工作内存&#xff08;或者称为…

CAS(比较并交换)学习CAS实现原子性+volatile实现可见性,cas与synchronized比较的优缺点

1、CAS底层原理&#xff1f; 自旋锁(cas思想)unsafe类&#xff0c;保证原子性靠的是unsafe类 1.首先可以看到&#xff1a; atomicInteger.getAndIncrement();getAndIncrement()的底层是 public final int getAndIncrement() {return unsafe.getAndAddInt(this, valueOffset,…

cas引出的ABA问题?如何解决?- 理解原子引用、时间戳(版本号)原子引用

ABA问题&#xff1a; 假如有两个线程1&#xff0c;2&#xff1b; cas下&#xff1a;1.线程取值完等待&#xff0c;2线程取值并把A改成B&#xff0c;有把B改成A&#xff0c;这是1线程执行会任务A还是原来的A没有发生改变&#xff0c;如果不在乎中间结果&#xff0c;只看收尾&am…

java -锁(公平、非公平锁、可重入锁【递归锁】、自旋锁)

1.公平锁、非公平锁 2.可重入锁&#xff08;递归锁&#xff09; 3.自旋锁 AtomicReference atomicReference new AtomicReference();//原子引用线程下面代码5秒钟自旋了10万次&#xff0c;还是很消耗CPU的 package HighConcurrency;import java.util.concurrent.TimeUnit; imp…

CountDownLatch,同步辅助类

public class CountDownLatchextends Object一个同步辅助类&#xff0c;在完成一组正在其他线程中执行的操作之前&#xff0c;它允许一个或多个线程一直等待。 假设定义一个计数器为 5。每个线程完成任务后计数减1计数器减为 0 则通知等待的线程。 用给定的计数 初始化 Count…

CyclicBarrier-同步辅助类

与CountDownLatch相反&#xff0c;CyclicBarrier是做加法 public class CyclicBarrierextends Object一个同步辅助类&#xff0c;它允许一组线程互相等待&#xff0c;直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中&#xff0c;这些线程必…