文章目录

  • 前言
  • 中缀表达式转后缀表达式
  • 计算后缀表达式
  • 计算形式公式
  • 声明

前言

数学计算的加减乘除人脑算很简单,但是放到计算中却需要进行一些转换,在正式写Java计算数学表达式前,我们需要先来介绍两个概念:前缀表达式、中缀表达式和后缀表达式;(这里的某缀指的是符号的位置)
中缀表达式:我们所接收的教育中所学的就为中缀表达式,形如(ab/c-d+e),也即表达式中的运算符号在数字的中间且有运算符的优先级。
后缀表达式:后缀表达式即运算符号位于操作数的后面,形如(ab
c/d-e+),需要从左往右计算,可以不用考虑优先级,是一种线性的计算,也是计算机易于计算的一种方式;
前缀表达式:前缀表达式可由后缀表达式可知,运算符号位于操作数之前,形如(±/*abcde),也是一种计算机易于计算的一种方式。
介绍完上面的数学表达式的三种方式以后,就解决了我们用Java计算数学表达式的第一步了,将中缀表达式(人类易于理解)转换为后缀表达式(计算机易于计算);

中缀表达式转后缀表达式

将中缀表达式转换为后缀表达式可以借助堆栈实现,具体转换方式;
(1)从左到右进行遍历
(2)如果是运算数,则直接输出
(3)如果是左括号,则直接压入堆栈(括号是最高优先级)入栈后变成优先级最低的,确保其它运算符号能够正常入栈。
如果遇到的是右括号,则说明这个括号中的式子已经结束了,弹出并输出栈顶元素直到遇到左括号为止,遇到左括号弹出但不输出;
如果遇到运算符(加、减、乘、除运算符),将该运算符与栈顶运算符进行比较,
如果优先级高于栈顶运算符则压入堆栈;如果优先级低于栈顶运算符则将栈顶运算符弹出并输出,并比较新的栈顶运算符直到优先级大于栈顶元素或者栈空的时候在将该运算符入栈。
如果处理完毕后,栈不为空,则依次弹出并输出。
代码如下:

public static String infixToSuffix(String expression) {// 创建操作符堆栈Stack<Character> stack = new Stack<>();// 要输出的后缀表达式字符串StringBuild suffix = new StringBuild();for (int i = 0; i < expression.length(); i++) {// 中间变量char temp;// 获取该中缀表达式的每一个字符进行判断char ch = expression.charAt(i);switch (ch) {// 过滤空格case ' ':break;// 遇到左括号直接入栈case '(':stack.push('(');break;// 遇到+、- 运算符,将栈中的所有运算符全部弹出,遇到堆栈中的左括号为止case '+':case '-':while (stack.size() != 0) {temp = stack.pop();if (temp == '(') {stack.push('(');break;}suffix.append(temp);}// 没有进入循环说明当前为第一次进入或者其他前面运算都有括号等情况导致栈已经为空,此时需要将符号进栈stack.push(ch);break;// 遇到*、/ 运算符,则将堆栈中的所有运算符全部弹出,遇到加号、减号以及左括号为止case '*':case '/':while (stack.size() != 0) {temp = stack.pop();if (temp == '+' || temp == '-' || temp == '(') {stack.push(temp);break;}suffix.append(temp);}// 没有进入循环说明当前为第一次进入或者其他前面运算都有括号等情况导致栈已经为空,此时需要将符号进栈stack.push(ch);break;// 遇到右括号,则弹出所有运算符直到遇到左括号为止,并抛弃左括号。case ')':while (!stack.isEmpty()) {temp = stack.pop();if (temp == '(') {// 这里左括号不重新入栈了break;}suffix.append(temp);}break;// 默认情况下,将作为操作数直接输出到队列中default:suffix.append(ch);break;}}// 如果堆栈不为空,则把剩余的运算符一次弹出,输出到队列中while (!stack.isEmpty()) {suffix.append(stack.pop());}// 返回后缀表达式return suffix.toString();}

我们做一下测试,将中缀表达式a+b*c+(d-e)/f-g 转换为后缀表达式(这里先用字母代替数字),main方式如下:

public static void main(String[] args) {System.out.println(Calculation.infixToSuffix("a+b*c+(d-e)/f-g"));}

转换后的后缀表达式为:abc*+de-f/+g-
打印每次for循环堆栈的大小以及输出能够更好的如和将中缀表达式转换为后缀表达式

com.zlc.otherproject.calculationutil.Calculation
第1次
堆栈中的数据大小0
输出为a
第2次
堆栈中的数据大小1
输出为a
第3次
堆栈中的数据大小1
输出为ab
第4次
堆栈中的数据大小2
输出为ab
第5次
堆栈中的数据大小2
输出为abc
第6次
堆栈中的数据大小1
输出为abc*+
第7次
堆栈中的数据大小2
输出为abc*+
第8次
堆栈中的数据大小2
输出为abc*+d
第9次
堆栈中的数据大小3
输出为abc*+d
第10次
堆栈中的数据大小3
输出为abc*+de
第11次
堆栈中的数据大小1
输出为abc*+de-
第12次
堆栈中的数据大小2
输出为abc*+de-
第13次
堆栈中的数据大小2
输出为abc*+de-f
第14次
堆栈中的数据大小1
输出为abc*+de-f/+
第15次
堆栈中的数据大小1
输出为abc*+de-f/+g
中缀表达式转换后缀表达式为:abc*+de-f/+g-Process finished with exit code 0

计算后缀表达式

计算后缀表达式还可以借助堆栈来实现,从左到右依次读取,如果为数字则直接入栈,遇到运算符则弹出栈顶元素与弹出栈顶元素后的新栈顶元素进行运算;需要注意的地方就是除法被除数不能为0这种了。(数值计算使用了BigDecimal)
计算后缀表达式代码如下:

    /*** 定义公式计算符号*/public static final String ADD = "+";public static final String SUBTRACTION = "-";public static final String MULTIPLICATION = "*";public static final String DIVISION = "/";public static BigDecimal suffixToArithmetic(String express) throws ArithmeticException {// 将后缀表达式分割成字符串数组,此处直接使用空白也可以对字符串进行分割!!// 定义一个操作符集合,用于判断是否为操作符(后缀表达式中已经没有了左右括号)List<String>  operatorList = Arrays.asList("+","-","*","/");String[] values = express.split("");Stack<BigDecimal> stack = new Stack<>();String value;for (String s : values) {// 这里最好是进行判断彻底消除空格,在该数组的第一位为一个隐形的空格,这里一定要注意在使用exp.split("")剔除空白""value = s;// 由于使用的是""截取导致在数组第一位上面的值为空白if (StringUtils.isBlank(value)) {continue;}// 如果遇到了数字,放入操作数栈等待计算if(!operatorList.contains(value)){stack.push(new BigDecimal((value)));} else {// 如果是运算符,则弹出栈顶的两个数进行计算// x为第一次弹出的栈顶元素,这里面的顺序不能错BigDecimal x = stack.pop();BigDecimal y = stack.pop();// 将运算结果重新压栈stack.push(calculate(x, y, value));}}// 弹出栈顶元素就是最终结果return stack.pop();}/*** 这里需要注意x为第一次弹出栈顶的数,所以下面的加减乘除使用y操作x* @param x 操作数* @param y 操作数* @param operator 操作符* @return  计算结果*/private static BigDecimal calculate(BigDecimal x, BigDecimal y, String operator) {BigDecimal calculateResult;switch (operator.trim()){case Calculation.ADD:calculateResult = y.add(x);break;case Calculation.SUBTRACTION:calculateResult = y.subtract(x);break;case Calculation.MULTIPLICATION:calculateResult = y.multiply(x);break;case Calculation.DIVISION:if (x.intValue() == 0){throw new ArithmeticException("被除数为0,无法计算!");}else {// 结果保留4位小数calculateResult = y.divide(x,4,RoundingMode.HALF_UP);}break;default:throw new ArithmeticException("无法运算的运算符!");}return calculateResult;}

我们做一下测试,计算中缀表达式1+2*3+(4-2)/2-4,计算结果为4,保丢4位小数位4.0000.

public static void main(String[] args) {String infixExpression = "1+2*3+(4-2)/2-4";String postfixExpression = Calculation.infixToSuffix(infixExpression);System.out.println("中缀表达式:" + infixExpression +"转换为后缀表达式后为:" + postfixExpression);System.out.println("计算结果为:" + Calculation.suffixToArithmetic(postfixExpression));}

计算结果如下:

中缀表达式:1+2*3+(4-2)/2-4转换为后缀表达式后为:123*+42-2/+4-
计算结果为:4.0000Process finished with exit code 0

计算形式公式

上面的例子我们计算的公式只能是公式中的数字已经确定好的,这样还不够灵活,下面使用26个小写的英文字母代替数字,使用字母作为形式计算数字,为相应的字母赋值,计算相应的数学公式计算结果,对上面的代码进行一些改造。

package com.zlc.javaproject.calculationutils;import org.apache.commons.lang.StringUtils;import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.regex.Pattern;import static java.util.regex.Pattern.compile;/*** @author Jacob* @version 1.0* @date 2020/9/14 20:43*/
public class Calculation {/*** 定义公式计算符号*/private static final String ADD = "+";private static final String SUBTRACTION = "-";private static final String MULTIPLICATION = "*";private static final String DIVISION = "/";/*** @param expression 计算公式* @param param 参数* @return  根据计算公式返回结果*/public static BigDecimal getCalculateResult(String expression, Map<String,String> param) throws ArithmeticException{return stringToArithmetic(expression, param);}/*** @param string 中缀表达式* @param map 公式形参实参map* @return 公式计算结果* @throws ArithmeticException 计算异常*/private static BigDecimal stringToArithmetic(String string, Map<String, String> map) throws ArithmeticException{return suffixToArithmetic(infixToSuffix(string), map);}/*** @param expression 中缀表达式* @return  后缀表达式*/public static String infixToSuffix(String expression) {// 创建操作符堆栈Stack<Character> stack = new Stack<>();StringBuilder suffix = new StringBuilder();for (int i = 0; i < expression.length(); i++) {// 中间变量char temp;// 获取该中缀表达式的每一个字符进行判断char ch = expression.charAt(i);switch (ch) {// 过滤空格case ' ':break;// 遇到左括号直接入栈case '(':stack.push('(');break;// 遇到+、- 运算符,将栈中的所有运算符全部弹出,遇到堆栈中的左括号为止case '+':case '-':while (stack.size() != 0) {temp = stack.pop();if (temp == '(') {stack.push('(');break;}suffix.append(temp);}// 没有进入循环说明当前为第一次进入或者其他前面运算都有括号等情况导致栈已经为空,此时需要将符号进栈stack.push(ch);break;// 遇到*、/ 运算符,则将堆栈中的所有运算符全部弹出,遇到加号、减号以及左括号为止case '*':case '/':while (stack.size() != 0) {temp = stack.pop();if (temp == '+' || temp == '-' || temp == '(') {stack.push(temp);break;}suffix.append(temp);}// 没有进入循环说明当前为第一次进入或者其他前面运算都有括号等情况导致栈已经为空,此时需要将符号进栈stack.push(ch);break;// 遇到右括号,则弹出所有运算符直到遇到左括号为止,并抛弃左括号。case ')':while (!stack.isEmpty()) {temp = stack.pop();if (temp == '(') {// 这里左括号不重新入栈了break;}suffix.append(temp);}break;// 默认情况下,将作为操作数直接输出到队列中default:suffix.append(ch);break;}}// 如果堆栈不为空,则把剩余的运算符一次弹出,输出到队列中while (!stack.isEmpty()) {suffix.append(stack.pop());}// 返回后缀表达式return suffix.toString();}/*** @param express 需要计算的后缀表达式* @return 计算结果* @throws ArithmeticException 计算异常*/public static BigDecimal suffixToArithmetic(String express, Map<String, String> map) throws ArithmeticException {// 使用正则表达式匹配数字Pattern pattern = compile("[a-z]");// 将后缀表达式分割成字符串数组,此处直接使用空白也可以对字符串进行分割!!// 定义一个操作符集合,用于判断是否为操作符(后缀表达式中已经没有了左右括号)List<String> operatorList = Arrays.asList("+","-","*","/");String[] values = express.split("");Stack<BigDecimal> stack = new Stack<>();String value;for (String s : values) {// 这里最好是进行判断彻底消除空格,在该数组的第一位为一个隐形的空格,这里一定要注意在使用exp.split("")剔除空白""value = s;// 由于使用的是""截取导致在数组第一位上面的值为空白if (StringUtils.isBlank(value)) {continue;}// 如果遇到了数字,放入操作数栈等待计算if(!operatorList.contains(value)){stack.push(new BigDecimal(map.get(value)));} else {// 如果是运算符,则弹出栈顶的两个数进行计算// x为第一次弹出的栈顶元素,这里面的顺序不能错BigDecimal x = stack.pop();BigDecimal y = stack.pop();// 将运算结果重新压栈stack.push(calculate(x, y, value));}}// 弹出栈顶元素就是最终结果return stack.pop();}/*** 这里需要注意x为第一次弹出栈顶的数,所以下面的加减乘除使用y操作x* @param x 操作数* @param y 操作数* @param operator 操作符* @return  计算结果*/private static BigDecimal calculate(BigDecimal x, BigDecimal y, String operator) {BigDecimal calculateResult;switch (operator.trim()){case Calculation.ADD:calculateResult = y.add(x);break;case Calculation.SUBTRACTION:calculateResult = y.subtract(x);break;case Calculation.MULTIPLICATION:calculateResult = y.multiply(x);break;case Calculation.DIVISION:if (x.intValue() == 0){throw new ArithmeticException("被除数为0,无法计算!");}else {// 结果保留4位小数calculateResult = y.divide(x,4, RoundingMode.HALF_UP);}break;default:throw new ArithmeticException("无法运算的运算符!");}return calculateResult;}public static void main(String[] args) {// 中缀表达式 1+2*3+(4-2)/2-4String infixExpression = "a+b*c+(d-b)/b-d";Map<String, String> params = new HashMap<>(16);params.put("a","1");params.put("b", "2");params.put("c","3");params.put("d","4");String postfixExpression = Calculation.infixToSuffix(infixExpression);System.out.println("中缀表达式:" + infixExpression +"转换为后缀表达式后为:" + postfixExpression);System.out.println("计算结果为:" + Calculation.getCalculateResult(infixExpression,params));}
}

运行结果如下:

中缀表达式:a+b*c+(d-b)/b-d转换为后缀表达式后为:abc*+db-b/+d-
计算结果为:4.0000

经过上面的代码改造就可以使计算更加的灵活方便。

声明

本文首发于香菜喵,打开微信随时随地读,文章下方 ↓ ↓ ↓

Java数学表达式计算(中缀转后缀表达式)相关推荐

  1. 后缀转中缀表达式_中缀转后缀表达式代码实现(下)及计算器完整版

    南故笙烟:中缀表达式转为后缀表达式​zhuanlan.zhihu.com 思路分析 1.初始化两个栈:运算符栈s1和储存中间结果的栈s2 2.从左至右扫描中缀表达式 3.遇到操作数时,将其压入s2 4 ...

  2. 前缀、中缀、后缀表达式及中缀转后缀表达式

    前缀表达式: 不含括号的算术表达式,而且是将运算符写在前面,操作数写在后面的表达式. 求法: 首先从右往左扫描表达式,从右边第一个字符判断,如果当前字符是数字,则一直到字符串的末尾再记录下来:如果是运 ...

  3. 表达式转换 (中缀转后缀表达式)

    算术表达式有前缀表示法.中缀表示法和后缀表示法等形式.日常使用的算术表达式是采用中缀表示法,即二元运算符位于两个运算数中间.请设计程序将中缀表达式转换为后缀表达式. 输入格式: 输入在一行中给出不含空 ...

  4. Java数据结构和算法(六)——前缀、中缀、后缀表达式

    前面我们介绍了三种数据结构,第一种数组主要用作数据存储,但是后面的两种栈和队列我们说主要作为程序功能实现的辅助工具,其中在介绍栈时我们知道栈可以用来做单词逆序,匹配关键字符等等,那它还有别的什么功能吗 ...

  5. 前缀、中缀和后缀表达式详解,中缀表达式到后缀表达式的转换规则,以及后缀表达式的计算规则,附计算代码

    1. 中缀.前缀和后缀表达式 1.1 中缀表达式 首先,中缀表达式的这个"缀"指运算符在两个操作数的位置.中缀表达式其实就是我们常用的算术表达式,比如 2 + 9 - (32 * ...

  6. 数据结构与算法——中缀转后缀表达式以及计算

    中缀表达式转后缀表达式 思路分析: 初始化两个栈:运算符栈s1 和储存中间结果的栈s2 从左至右扫描中缀表达式 遇到操作数,将其压入s2 遇到运算符时,比较其与s1 栈顶运算符的优先级 如果s1 为空 ...

  7. 前缀、中缀、后缀表达式及其相互转化的Java实现

    一.中缀表达式转换为前缀.后缀表达式 给个中缀表达式:a+b*c-(d+e) 首先根据运算符的优先级给所有运算单位加括号:((a+(b*c))-(d+e)) 将运算符号移动到对应括号的前面然后去掉所有 ...

  8. 前缀、中缀、后缀表达式(转载)

    关键字:概念, 前缀表达式, 前缀记法, 中缀表达式, 中缀记法, 波兰式, 后缀表达式, 后缀记法, 逆波兰式 它们都是对表达式的记法,因此也被称为前缀记法.中缀记法和后缀记法.它们之间的区别在于运 ...

  9. 一行文章让你搞懂什么是前缀、中缀、后缀表达式以及它们之间的相互转换

    一.什么前缀.中缀.后缀表达式(使用 8*(5+6)-1的例子) 1.中缀表达式:8*(5+6)-1:(也就是我们平常所见的运算式) 2.后缀表达式:8 5 6 + * 1 - :计算机是怎么运算的呢 ...

最新文章

  1. leetcode-25 K个一组反转链表
  2. qt4的quick程序升级到qt5_最新8月书单出炉!送给你程序员
  3. 最后一次作业-----课程总结
  4. com.mysql.cj.exceptions.InvalidConnectionAttributeException
  5. vue获取当前月最后一天_只争朝夕,不负韶华——站在2020年第一天,回望2019最后的两个月...
  6. php ueditor怎么用,ueditor PHP版本使用方法
  7. 用C#实现文件夹拷贝
  8. java实现验证码生成工具类
  9. 计算机组成原理——微程序设计
  10. 金融科技在互联网金融行业性风险防范领域的应用
  11. java技术英文名词读音_Java开发,Java development,音标,读音,翻译,英文例句,英语词典...
  12. 启明云端分享|IDO-SOM3828模块,你值得拥有。
  13. Vue教程(四十七)Promise基本介绍与使用
  14. 百度LBS开放平台Android SDK产品使用
  15. CCF CSP 公共钥匙盒 JAVA 201709-2 100分
  16. 解决 CLion 出现中文乱码问题【亲测有效】
  17. 大数据共享模糊查找_120多个查找知识共享媒体的地方
  18. Sublime Text3 多行注释
  19. Zookeeper--四字命令
  20. 【第十篇】商城系统-性能测试

热门文章

  1. 向顶尖高手学习技巧,方法,认知,成长路径
  2. 免费恢复安卓手机SD卡上的图片和视频文件
  3. hibernate.cgf.xml
  4. vue中打印表格,打印不全的问题
  5. linux 画图开源工具有哪些,分享|Drawing:一款开源的类似微软画图的 Linux 桌面应用...
  6. IDEA构建VUE脚手架
  7. keras入门——使用LSTM预测股票价格
  8. go语言读文件写文件
  9. Struts2实现文件上传与下载
  10. 第一天给0.01元,第二天给0.02元,以此类推,每一天是前一天的2倍,连续一个月结果