1 前缀表达式介绍

前缀表达式又称波兰式,前缀表达式的运算符位于操作数之前
举例说明: (3+4)×5-6 对应的前缀表达式就是 - × + 3 4 5 6

1.1 前缀表达式的计算机求值过程

从右至左扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(栈顶元素和次顶元素),并将结果入栈;重复上述过程直到表达式最左端,最后运算得出的值即为表达式的结果。

1.2 前缀表达式的计算过程举例说明

例如: (3+4)×5-6 对应的前缀表达式就是 - × + 3 4 5 6 , 针对前缀表达式求值步骤如下:

  1. 从右至左扫描,将6、5、4、3压入堆栈
  2. 遇到+运算符,因此弹出3和4(3为栈顶元素,4为次顶元素),计算出3+4的值,得7,再将7入栈
  3. 接下来是×运算符,因此弹出7和5,计算出7×5=35,将35入栈
  4. 最后是-运算符,计算出35-6(先弹出的数—后弹出的数)的值,即29,由此得出最终结果

2 中缀表达式介绍

中缀表达式就是常见的运算表达式,如(3+4)×5-6
中缀表达式的求值是我们人最熟悉的,但是对计算机来说却不好操作(前面我们讲的案例就能看的这个问题),因此,在计算结果时,往往会将中缀表达式转成其它表达式来操作(一般转成后缀表达式.)

关于用中缀表达式实现简单四则运算计算器情况下面链接对应的博文

https://blog.csdn.net/weixin_40139164/article/details/108964924

3 后缀表达式介绍

后缀表达式又称逆波兰表达式,与前缀表达式相似,只是运算符位于操作数之后
举例说明: (3+4)×5-6 对应的后缀表达式就是 3 4 + 5 × 6 –

3.1 后缀表达式的计算机求值过程

从左至右扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(次顶元素 和 栈顶元素),并将结果入栈;重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果。

3.2 后缀表达式的计算过程举例说明

例如: (3+4)×5-6 对应的后缀表达式就是 3 4 + 5 × 6 - , 针对后缀表达式求值步骤如下:

  1. 从左至右扫描,将3和4压入堆栈;
  2. 遇到+运算符,因此弹出4和3(4为栈顶元素,3为次顶元素),计算出3+4的值,得7,再将7入栈;
  3. 将5入栈;
  4. 接下来是×运算符,因此弹出5和7,计算出7×5=35,将35入栈;
  5. 将6入栈;
  6. 最后是-运算符,计算出35-6(后弹出的数—先弹出的数)的值,即29,由此得出最终结果

3.3 实现逆波兰计算器

代码实现:

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;public class PolandNotation {public static void main(String[] args) {//先定义给逆波兰表达式//(30+4)×5-6  => 30 4 + 5 × 6 - => 164// 4 * 5 - 8 + 60 + 8 / 2 => 4 5 * 8 - 60 + 8 2 / + //测试 //说明为了方便,逆波兰表达式 的数字和符号使用空格隔开//String suffixExpression = "30 4 + 5 * 6 -";String suffixExpression = "4 5 * 8 - 60 + 8 2 / +"; // 76//思路//1. 先将 "3 4 + 5 × 6 - " => 放到ArrayList中//2. 将 ArrayList 传递给一个方法,遍历 ArrayList 配合栈 完成计算List<String> list = getListString(suffixExpression);System.out.println("rpnList=" + list);int res = calculate(list);System.out.println("计算的结果是=" + res);}//将一个逆波兰表达式, 依次将数据和运算符 放入到 ArrayList中public static List<String> getListString(String suffixExpression) {//将 suffixExpression 分割String[] split = suffixExpression.split(" ");List<String> list = new ArrayList<String>();for(String ele: split) {list.add(ele);}return list;}//完成对逆波兰表达式的运算/** 1)从左至右扫描,将3和4压入堆栈;2)遇到+运算符,因此弹出4和3(4为栈顶元素,3为次顶元素),计算出3+4的值,得7,再将7入栈;3)将5入栈;4)接下来是×运算符,因此弹出5和7,计算出7×5=35,将35入栈;5)将6入栈;6)最后是-运算符,计算出35-6的值,即29,由此得出最终结果*/public static int calculate(List<String> ls) {// 创建栈, 只需要一个栈即可Stack<String> stack = new Stack<String>();// 遍历 lsfor (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());}}

4 中缀表达式转后缀表达式

思路分析:

1、初始化两个栈:运算符栈s1和储存中间结果的栈s2;
2、从左至右扫描中缀表达式;
3、遇到操作数时,将其压s2;
4、遇到运算符时,比较其与s1栈顶运算符的优先级:
   4.1如果s1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
   4.2否则,若优先级比栈顶运算符的高,也将运算符压入s1;
   4.3否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4.1)与s1中新的栈顶运算符相比较;
5、遇到括号时: (1) 如果是左括号“(”,则直接压入s1 (2) 如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
6、重复步骤2至5,直到表达式的最右边
7、将s1中剩余的运算符依次弹出并压入s2
8、依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式

举例说明:

将中缀表达式“1+((2+3)×4)-5”转换为后缀表达式的过程如下

结果为:"1 2 3 + 4 × + 5 –"

代码实现:

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;public class PolandNotation {public static void main(String[] args) {// 完成将一个中缀表达式转成后缀表达式的功能// 说明// 1. 1+((2+3)×4)-5 => 转成 1 2 3 + 4 × + 5 –// 2. 因为直接对str 进行操作,不方便,因此 先将 "1+((2+3)×4)-5" =》 中缀的表达式对应的List// 即 "1+((2+3)×4)-5" => ArrayList [1,+,(,(,2,+,3,),*,4,),-,5]// 3. 将得到的中缀表达式对应的List => 后缀表达式对应的List// 即 ArrayList [1,+,(,(,2,+,3,),*,4,),-,5] =》 ArrayList [1,2,3,+,4,*,+,5,–]String expression = "1+((2+3)*4)-5";// 注意表达式List<String> infixExpressionList = toInfixExpressionList(expression);System.out.println("中缀表达式对应的List=" + infixExpressionList); // ArrayList [1,+,(,(,2,+,3,),*,4,),-,5]List<String> suffixExpreesionList = parseSuffixExpreesionList(infixExpressionList);System.out.println("后缀表达式对应的List" + suffixExpreesionList); // ArrayList [1,2,3,+,4,*,+,5,–]System.out.printf("expression=%d", calculate(suffixExpreesionList)); // ?// 即 ArrayList [1,+,(,(,2,+,3,),*,4,),-,5] =》 ArrayList [1,2,3,+,4,*,+,5,–]// 方法:将得到的中缀表达式对应的List => 后缀表达式对应的Listpublic static List<String> parseSuffixExpreesionList(List<String> ls) {// 定义两个栈Stack<String> s1 = new Stack<String>(); // 符号栈// 说明:因为s2 这个栈,在整个转换过程中,没有pop操作,而且后面我们还需要逆序输出// 因此比较麻烦,这里我们就不用 Stack<String> 直接使用 List<String> s2// Stack<String> s2 = new Stack<String>(); // 储存中间结果的栈s2List<String> s2 = new ArrayList<String>(); // 储存中间结果的Lists2// 遍历lsfor (String item : ls) {// 如果是一个数,加入s2if (item.matches("\\d+")) {s2.add(item);} // 如果s1为空,则直接将此运算符入栈;else if (s1.size() == 0) {s1.push(item);} // 如果是左括号“(”,则直接压入s1else if (item.equals("(")) {s1.push(item);// 如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃} else if (item.equals(")")) {while (!s1.peek().equals("(")) {s2.add(s1.pop());}s1.pop();// !!! 将 ( 弹出 s1栈, 消除小括号} //栈顶运算符为左括号“(”,则直接将此运算符入栈;else if (s1.peek().equals("(")) {s1.push(item);} else {// 当item的优先级小于等于s1栈顶运算符, 将s1栈顶的运算符弹出并加入到s2中,再次转到(4.1)与s1中新的栈顶运算符相比较             // 问题:我们缺少一个比较优先级高低的方法while (s1.size() != 0 && Operation.getValue(s1.peek()) >= Operation.getValue(item)) {s2.add(s1.pop());}// 否则,若优先级比栈顶运算符的高,也将运算符压入s1;// 还需要将item压入栈s1.push(item);}}// 将s1中剩余的运算符依次弹出并加入s2while (s1.size() != 0) {s2.add(s1.pop());}return s2; // 注意因为是存放到List, 因此按顺序输出就是对应的后缀表达式对应的List}// 方法:将 中缀表达式转成对应的List// s="1+((2+3)×4)-5";public static List<String> toInfixExpressionList(String s) {// 定义一个List,存放中缀表达式 对应的内容List<String> ls = new ArrayList<String>();int i = 0; // 这时是一个指针,用于遍历 中缀表达式字符串String str; // 对多位数的拼接char c; // 每遍历到一个字符,就放入到cdo {// 如果c是一个非数字,我需要加入到lsif ((c = s.charAt(i)) < 48 || (c = s.charAt(i)) > 57) {ls.add("" + c);i++; // i需要后移} else { // 如果是一个数,需要考虑多位数str = ""; // 先将str 置成"" '0'[48]->'9'[57]while (i < s.length() && (c = s.charAt(i)) >= 48 && (c = s.charAt(i)) <= 57) {str += c;// 拼接i++;}ls.add(str);}} while (i < s.length());return ls;// 返回}// 将一个逆波兰表达式, 依次将数据和运算符 放入到 ArrayList中public static List<String> getListString(String suffixExpression) {// 将 suffixExpression 分割String[] split = suffixExpression.split(" ");List<String> list = new ArrayList<String>();for (String ele : split) {list.add(ele);}return list;}// 完成对逆波兰表达式的运算/** 1)从左至右扫描,将3和4压入堆栈; 2)遇到+运算符,因此弹出4和3(4为栈顶元素,3为次顶元素),计算出3+4的值,得7,再将7入栈; 3)将5入栈;* 4)接下来是×运算符,因此弹出5和7,计算出7×5=35,将35入栈; 5)将6入栈; 6)最后是-运算符,计算出35-6的值,即29,由此得出最终结果*/public static int calculate(List<String> ls) {// 创建栈, 只需要一个栈即可Stack<String> stack = new Stack<String>();// 遍历 lsfor (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:System.out.println("不存在该运算符" + operation);break;}return result;}}

前缀表达式(波兰表达式)介绍及其代码实现(Java)相关推荐

  1. 前缀(波兰表达式) 中缀 后缀(逆波兰表达式)

    前缀.中缀.后缀表达式(逆波兰表达式) 本文转自https://www.cnblogs.com/chensongxian/p/7059802.html 介绍 前缀表达式.中缀表达式.后缀表达式都是四则 ...

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

    栈的三种表达式:前缀.中缀和后缀表达式,后缀也叫逆波兰表达式 前缀(波兰表达式) 中缀(对人来讲很好理解,对于计算机来讲就方便了,一般会把中缀表达式转换成后缀表达式) 后缀(逆波兰表达式) 计算过程 ...

  3. 数据结构:前缀,中缀,后缀表达式(逆波兰表达式)

    前缀表达式(波兰表达式) 前缀表达式的运算符位于操作数之前. 比如 (1+2)*3-4  对应的前缀表达式就是: - * + 1 2 3 4 前缀表达式的计算机求值 从右至左扫描表达式,遇到数字时,就 ...

  4. 前缀中缀后缀表达式的计算求值

    原文在这里 表达式 前缀表达式(波兰表达式) 前缀表达式又称波兰式,前缀表达式的运算符位于操作数之前 举例说明: (3+4)×5-6 对应的前缀表达式就是 - × + 3 4 5 6 前缀表达式求值 ...

  5. codevs2574 波兰表达式

    题目描述 Description 对于 加.减.乘.除这种四则运算的表达式,我们使用的是先乘除.后加减的从左到右的顺序进行运算,如果要指定特定的顺序,就要增加括号进行表达,比如 (A+B)*C , A ...

  6. 前缀表达式后缀表达式_你知道波兰表达式和逆波兰表达式吗

    什么是波兰表达式 我们日常的运算表达式通常是如下形式,这种成为中缀表达式,也就是运算符在运算数的中间.这种表达式人类很容易识别,并根据其进行计算,但计算机识别这种表达式非常困难. a + b * (c ...

  7. 1198:逆波兰表达式(递归,前缀表达式,波兰表达式)

    前言:题干描述有问题 题干明明是前缀表达式呀,前缀表达式就是波兰表达式,怎么能叫逆波兰表达式呢?所以题目描述有问题! 逆波兰表达式,也叫后缀表达式 : 举例:a+b  --> a b +. 波兰 ...

  8. 逆波兰表达式简单介绍

    逆波兰表达式又叫做后缀表达式.在通常的表达式中,二元运算符总是置于与之相关的两个运算对象之间,所以,这种表示法也称为中缀表示.波兰逻辑学家J.Lukasiewicz于1929年提出了另一种表示表达式的 ...

  9. 波兰表达式(Polish Notation)简要介绍

    波兰表达式的由来 1920年,波兰科学家扬·武卡谢维奇(Jan ukasiewicz)发明了一种不需要括号的计算表达式的表示法将操作符号写在操作数之前,也就是前缀表达式,即波兰式(Polish Not ...

最新文章

  1. share一下一线大厂是怎么招聘技术岗的?
  2. 15 -Flask构建弹幕微电影网站-基于角色的访问控制
  3. 帆软正则表达式定义规则
  4. 大数运算(5)——大数除法(取模、取余)
  5. crtsiii型无砟轨道板_为什么高铁轨道不像普快列车轨道那样铺碎石?
  6. Windows Server 2008虚拟机ERP压力测试(5)
  7. 【数据结构与算法】之深入解析“TinyURL加密与解密”的求解思路与算法示例
  8. java 数据结构详解,数组,集合,HashMap
  9. PowerShell 2.0 实践(十一)管理 TFS 2010 (2)
  10. Homework-201521410028
  11. Java把日期转为周几
  12. 知识图谱(KG)中的同义词挖掘
  13. android的wifi开发,android开发教程之wifi开发示例
  14. 讲教资备考时间和精力
  15. To prevent a memory leak the JDBC Driver has been forcibly
  16. 老板拖欠工资怎么办?
  17. python能够设置标签背景色的属性是_Python Pmw EntryField背景色属性
  18. 家用计算机做raid 2018,让电脑速度翻倍的方法,手把手教你组建RAID!
  19. 一个前端的MONGO救赎--1
  20. “希希敬敬对”团队作业-敏捷冲刺2

热门文章

  1. Manjaro 安装 Wacom 驱动
  2. 用计算机怎么按pka,由pka怎么求ka
  3. 机器学习读书笔记:决策树
  4. 简述如何编辑出一篇漂亮的微信公众号文章
  5. AppInventor中调用百度地图方法
  6. 网易开源游戏服务器框架-Pomelo实践(一)
  7. 解决主机无法通过网络访问虚拟机的问题
  8. maxlength不起作用android,Android EditText设置Filter以后(xml布局文件中maxLength不起作用的解决办法)...
  9. unity游戏开发毕设_基于Unity3D射击游戏开发与实现
  10. 贪心——Luogu2255 [USACO14JAN]记录奥林比克