一.简介
对于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){