一.简介

对于1+((2*3)-4)/2 的数学表达式怎么求值?

分析:
数学表达式求值有优先级,不能简单的从左往右依次计算, 需要从优先级高的开始计算

中缀表达式是一种通用的算术或逻辑公式表示方法,操作符以中缀形式处于操作数的中间。 人的大脑很容易理解与分析中缀表达式,但计算机对中缀表达式却是很复杂的,计算前缀或后缀表达式的值非常简单,因此计算表达式的值时,通常需要先将中缀表达式转换为前缀或后缀表达式,然后再进行求值。

1.前缀和后缀表达式已经内在地包含运算顺序,因此不用括号来确定优先级

2.前缀和后缀表达式适合计算机计算 ,前缀表达式和后缀表达式计算的时候都是从一个方向扫描表达式,遇到数字压入栈,遇到运算符弹出栈顶的两个数进行运算并将结果入栈,重复直到结束

二.中缀表达式

运算符在数值之间就是中缀表达式,如1+((2*3)-4)/2,数学表达式天然就是中缀表达式。

从左往右遍历每个字符:

1.字符是数值就入栈到数值栈中

2.字符为运算符就和上一个运算符比较优先级(没有就直接入栈,左括号"(" 直接入栈);小于上一个运算符优先级就出栈2个数值,出栈1个运算符并计算结果入栈,再入栈当前运算符;如果为")" 则计算括号内的数值并入栈,直到符号栈符号为"("

数学表达式解析完成后:

从数值栈出栈2个数值,符号栈出栈一个符号,计算结果并入栈,直到栈中只有一个数值

流程图:

实现:
MathExpression.java

package com.vincent;import java.util.HashMap;
import java.util.Map;public class MathExpression {/*** 计算中缀表达式* @param exp       待计算的中缀表达式* @return*/public static int calcExpression(String exp){exp = exp.replace(" ","");java.util.LinkedList<Integer> numStack = new java.util.LinkedList<>();java.util.LinkedList<String> opStack = new java.util.LinkedList<>();for(int i=0;i<exp.length();i++){String ch = exp.substring(i,i+1);if(operPriority(ch) != null){//获取的是运算符if(opStack.size() == 0 || ch.equals("(")){opStack.addLast(ch);}else if(ch.equals(")")){//有括号表达式,计算整个括号表达式结果并入栈while(!opStack.getLast().equals("(")){int num2 = numStack.removeLast();int rst = calc(numStack.removeLast(),num2,opStack.removeLast());numStack.addLast(rst);}//去除"(" 括号opStack.removeLast();}else if(operPriority(opStack.getLast()) < operPriority(ch) && !opStack.getLast().equals("(")){//当前运算符优先级低于上一个运算符优先级int num2 = numStack.removeLast();int rst = calc(numStack.removeLast(),num2,opStack.removeLast());numStack.addLast(rst);opStack.addLast(ch);}else{opStack.addLast(ch);}}else{//获取的是非运算符int pos = i+1;while(pos < exp.length() && operPriority(exp.substring(pos,pos+1)) == null){pos++;}numStack.addLast(Integer.parseInt(exp.substring(i,pos)));i = pos - 1;}}while(numStack.size() > 1){int num2 = numStack.removeLast();int rst = calc(numStack.removeLast(),num2,opStack.removeLast());numStack.addLast(rst);}return numStack.removeLast();}/*** 获取符号优先级,对于运算符其值越低优先级越高,如果是改变运算符优先级的符号(如括号)获取将是负数* @param op* @return*/public static Integer operPriority(String op){Map<String,Integer> opMap = new HashMap<>();opMap.put("+",2);opMap.put("-",2);opMap.put("*",1);opMap.put("/",1);opMap.put("(",-1);opMap.put(")",-1);return opMap.get(op);}public static int calc(int num1,int num2,String op){if(op.equals("+")){return num1 + num2;}else if(op.equals("-")){return num1 - num2;}else if(op.equals("*")){return num1 * num2;}else if(op.equals("/")){return num1 / num2;}throw new IllegalArgumentException();}
}

Main.java

package com.vincent;public class Main {public static void main(String[] args) throws Exception{String exp = "1+((2*3)-4)/2";System.out.println(MathExpression.calcExpression(exp));}
}

效果:

中缀表达式转为后缀、前缀的思路和计算中缀表达式基本一样,只是中缀转后缀是从字符串头部解析,中缀转前缀是从字符串尾部开始解析。

三.后缀(逆波兰)表达式

MathExpression.java 增加如下方法

/**
* 数学表达式转化为后缀(逆波兰)表达式* @param exp       待转化的数学表达式* @return          后缀表达式*/public static String toSuffixExpression(String exp){exp = exp.replace("\\s","");java.util.LinkedList<String> exprStack = new java.util.LinkedList<>();java.util.LinkedList<String> opStack = new java.util.LinkedList<>();for(int i=0;i<exp.length();i++){char ch = exp.charAt(i);if(operPriority(ch+"") != null){if(opStack.size() == 0 || ch == '('){opStack.addLast(ch+"");}else if(ch == ')'){while(!opStack.getLast().equals("(")) {exprStack.addLast(opStack.removeLast());}//出栈左括号"("opStack.removeLast();}else if(operPriority(opStack.getLast()) < operPriority(ch+"") && !opStack.getLast().equals("(")){//符号栈顶符号优先级较高exprStack.addLast(opStack.removeLast());opStack.addLast(ch+"");}else{opStack.addLast(ch+"");}}else{int pos = i+1;//数字字符0-9编码为48-57while(pos < exp.length() && exp.charAt(pos)>=48 && exp.charAt(pos)<=57){pos++;}exprStack.addLast(exp.substring(i,pos));i = pos -1;}}while(opStack.size() > 0){exprStack.addLast(opStack.removeLast());}StringBuilder rst = new StringBuilder();while(exprStack.size() > 0){rst.append(exprStack.removeLast()).append(" ");}rst.reverse();return rst.toString().trim();}public static int calcSuffixExpression(String exp){String[] parts = exp.split(" ");java.util.LinkedList<Integer> stack = new java.util.LinkedList<>();for(String part : parts){if(operPriority(part) == null){stack.addLast(Integer.parseInt(part));}else{//第一个出栈的是操作数2int num2 = stack.removeLast();int rst = calc(stack.removeLast(),num2,part);stack.addLast(rst);}}return stack.removeLast();}

Main.java

package com.vincent;public class Main {public static void main(String[] args) throws Exception{String exp = "1+((2*3)-4)/2";System.out.println(MathExpression.calcExpression(exp));System.out.println("后缀表达式:" + MathExpression.toSuffixExpression(exp));System.out.println(MathExpression.calcSuffixExpression(MathExpression.toSuffixExpression(exp)));}
}

效果:

四.前缀表达式

前缀表达式是后缀表达式的反向遍历操作,即从表达式尾部向头部开始解析操作。

MathExpression.java 增加如下方法:

/*** 解析数学表达式为前缀表达式* @param exp* @return*/public static String toPrefixExpression(String exp){exp = exp.replace("\\d","");java.util.LinkedList<String> exprStack = new java.util.LinkedList<>();java.util.LinkedList<String> opStack = new java.util.LinkedList<>();for(int i=exp.length()-1;i>=0;i--){char ch = exp.charAt(i);if(operPriority(ch+"") != null){if(opStack.size() == 0 || ch == ')'){opStack.addLast(ch+"");}else if(ch == '('){while(!opStack.getLast().equals(")")){exprStack.addLast(opStack.removeLast());}//移除符号栈中的右括号")"opStack.removeLast();}else if(operPriority(opStack.getLast()) < operPriority(ch+"") && !opStack.getLast().equals(")")){exprStack.addLast(opStack.removeLast());opStack.addLast(ch+"");}else{opStack.addLast(ch+"");}}else{int pos = i - 1;while(pos >=0 && exp.charAt(pos) >= 48 && exp.charAt(pos) <= 57){pos--;}exprStack.addLast(exp.substring(pos+1,i+1));i = pos + 1;}}while(opStack.size() > 0){exprStack.addLast(opStack.removeLast());}StringBuilder rst = new StringBuilder();while(exprStack.size() > 0){rst.append(exprStack.removeLast()).append(" ");}return rst.toString().trim();}/*** 计算前缀表达式* @param exp       前缀表达式* @return*/public static int calcPrefixExpression(String exp){String[] parts = exp.split(" ");java.util.LinkedList<Integer> stack = new java.util.LinkedList<>();for(int i=parts.length-1;i>=0;i--){if(operPriority(parts[i]) == null){stack.addLast(Integer.parseInt(parts[i]));}else{//第一个出栈的是第一个操作数int num1 = stack.removeLast();int rst = calc(num1,stack.removeLast(),parts[i]);stack.addLast(rst);}}return stack.removeLast();}

Main.java

package com.vincent;public class Main {public static void main(String[] args) throws Exception{String exp = "1+((2*3)-4)/2";System.out.println(MathExpression.calcExpression(exp));System.out.println("后缀表达式:" + MathExpression.toSuffixExpression(exp));System.out.println(MathExpression.calcSuffixExpression(MathExpression.toSuffixExpression(exp)));System.out.println("前缀表达式:" + MathExpression.toPrefixExpression(exp));System.out.println(MathExpression.calcPrefixExpression(MathExpression.toPrefixExpression(exp)));}
}

效果:

五.总结

不管是中缀、后缀、前缀表达式在解析运算符时都需要和上一个运算符比较优先级,只有在优先级小于上一个运算符优先级时才能知道上一个运算符优先级较高,故才不会影响计算的优先级

前缀和后缀表达式已经内在地包含运算顺序,因此不用括号来确定优先级

中缀、后缀、前缀表达式相关推荐

  1. pnd1 c语言,c语言实现中缀后缀前缀表达式相互转化并求值

    <c语言实现中缀后缀前缀表达式相互转化并求值>由会员分享,可在线阅读,更多相关<c语言实现中缀后缀前缀表达式相互转化并求值(21页珍藏版)>请在人人文库网上搜索. 1.1)表达 ...

  2. 使用栈解决的一类经典问题:表达式转换及求值;中缀表达式;前缀表达式,后缀表达式,中缀转前缀;中缀转后缀;后缀表达式求值;波兰式,逆波兰式

    文章目录 背景知识 表达式转换问题(考研经典) 一:手工转换 (1)中缀转前缀和中缀转后缀 (2)前缀转中缀和后缀转中缀 二:用栈实现表达式转换 (1)中缀转后缀 (2)中缀转前缀 表达式计算问题(使 ...

  3. 前缀表达式的计算机求值

    前缀表达式的计算机求值特点 引例:某表达式的前缀形式为"+ -*^ABCD/E/F+GH",那么它的中缀形式为? 前缀表达式的操作 前缀表达式是一种没有括号的算术表达式,就是前序表 ...

  4. python【数据结构与算法】表达式(前缀中缀后缀表达式)与Two fork tree

    文章目录 1 相关概念 2 与二叉树关系 3 表达式转换 4 另一种方法 1 相关概念 前缀表达式(Prefix Notation)是指将运算符写在前面操作数写在后面的不包含括号的表达式,而且为了纪念 ...

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

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

  6. 前缀 中缀 后缀表达式

    1.前缀表达式叫波兰式,后缀叫逆波兰式 2.中缀表达式转另外两个比较简单,前后缀装中缀较麻烦 3.问题分求表达式还是求值,如果是求值则需要两个栈,一个是操作符栈,一个是操作数栈,等操作符栈入栈完毕后依 ...

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

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

  8. 中缀表达式到前缀表达式和后缀表达式

    1.算法思路 转化为后缀:从左到右遍历中缀表达式,遇到操作数,输出,遇到操作符,当前操作符的优先级大于栈顶操作符优先级,进栈,否则,弹出栈顶优先级大于等于当前操作符的操作符,当前操作符进栈.     ...

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

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

  10. 中缀表达式转换成前缀表达式和后缀表达式的极其简单方法

    35,15,+,80,70,-,*,20,/ //后缀表达方式 (((35+15)*(80-70))/20)=25 //中缀表达方式 /,*,+,35,15,-,80,70, 20 //前缀表达方式 ...

最新文章

  1. Axure RP使用攻略--入门级(七)之axure元件使用思路的补充
  2. 域名的购买,备案,解析以及绑定云服务器上的项目
  3. Intellij自动生成测试类
  4. python实现辗转相除法求最大公约数和最小公倍数
  5. javaone_旅行报告:JavaOne 2013 –重归荣耀
  6. AcWing之二维数组的查找
  7. 软件工程网络15个人阅读作业1(201521123029 郑佳明)
  8. 上证50基金有哪些_定投基金(易方达上证50指数A)
  9. android 跟随动画,Android实现View拖拽跟随手指移动效果
  10. asp 文本转时间_ASP.NET Core界面开发,DevExpress v19.2增强富文本编辑器功能
  11. matlab hamming 原理,Matlab中加汉明窗 ahmming 作用
  12. 贾俊平统计学思维导图- 第六章 统计量及其抽样分布
  13. 如何选择适合你的兴趣爱好(二十四),京剧
  14. 小学计算机教师面试试题及答案,2019上半年小学信息技术教师资格证面试试题及答案(精选)第一批...
  15. java-枚举类的定义及使用
  16. qq飞车找不到服务器了,QQ飞车体验服务器专区
  17. nmn是真的还是假的,如何鉴别高质量的nmn,方法一览
  18. ZwSe2团队共识V0.1
  19. 关于网站运营的研究_海外新媒体代运营_自媒体运营有哪些
  20. win7电脑恢复系统设置或计算机点不了,主编解答win7电脑突然进不了系统如何恢复的解决手段...

热门文章

  1. 中兴CT220终端机资料
  2. 淘宝课程学习如何安排太原网络营销师强烈推荐
  3. Live800:用在线客服系统,换你更少的等待
  4. 工行银企互联接入详解(2)--下载证书
  5. 解决Manjaro KDE安装中文新字体后不显示默认字体而是新安装的字体的问题
  6. 老手机秒变监控器+监听器
  7. 吉他入门教程之吉他音阶训练——使用方法
  8. mysql数据库原理分析
  9. 微信如何导出聊天记录亲测可用
  10. [攻城狮计划(三)] —— 看门狗定时器