如何处理数学表达式(一般是字符串型的),如:(1+2*3/4+5+(6*7)/8)。
处理思路:
1、将表达式转换为后缀表达式(也称为逆波兰表达式);
2、计算后缀表达式。
想了解后缀表达式,请参考百度百科:后缀表达式百度百科
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
public class StackDemo {
private static Map<String, Character> OPER_CHAR_MAP = null;
public static double calMathExpression(String expression) throws Exception {
expression = expression.trim().replaceAll(" ", "");
System.out.println(convertToRPN(expression));
return calRPN(convertToRPN(expression));
}
/**
* 初始化四则运算符map +、-、*(×)、/(÷) ()
*/
private static void initOperCharMap() {
if (OPER_CHAR_MAP == null || OPER_CHAR_MAP.isEmpty()) {
OPER_CHAR_MAP = new HashMap<>();
Character additon = new Character("+", 0);
Character subtraction = new Character("-", 0);
Character multiplication = new Character("*", 1);
Character division = new Character("/", 1);
Character left_bracket = new Character("(", 2);
Character right_bracket = new Character(")", 2);
OPER_CHAR_MAP.put("+", additon);
OPER_CHAR_MAP.put("-", subtraction);
OPER_CHAR_MAP.put("×", multiplication);
OPER_CHAR_MAP.put("*", multiplication);
OPER_CHAR_MAP.put("÷", division);
OPER_CHAR_MAP.put("/", division);
OPER_CHAR_MAP.put("(", left_bracket);
OPER_CHAR_MAP.put(")", right_bracket);
additon = null;
subtraction = null;
multiplication = null;
division = null;
left_bracket = null;
right_bracket = null;
}
}
/**
* 把标准四则表达式转为后缀表达式,以" "分隔每个数字
*/
private static String convertToRPN(String expression) throws Exception {
StringBuffer rpn_expression = new StringBuffer();
Stack<Character> char_stack = new Stack<>();
// 表达式按照每个字符拆分,考虑多位数,因此在遇到运算符前,用temp累计
StringBuffer temp = new StringBuffer();
// "(" 出现的次数
int left_bracket_cnt = 0;
for (int i = 0; i < expression.length(); i++) {
String s = expression.substring(i, i + 1);
if (isOperationalCharacter(s) != null || i == expression.length() - 1) {
try {
// 输出temp中的数字
if (temp.length() > 0) {
double num = Double.parseDouble(temp.toString());
rpn_expression.append(num);
// 分隔符
rpn_expression.append(" ");
// 初始化temp
temp = new StringBuffer();
}
// 输出运算符
Character c = OPER_CHAR_MAP.get(s);
if (char_stack.isEmpty()) {
char_stack.push(c);
} else {
switch (c.getValue()) {
case "(":
// "("直接入栈,等匹配后面的"("
char_stack.push(c);
left_bracket_cnt++;
break;
case "*":
case "/":
case "+":
case "-":
// 如果当前的运算不优先于栈顶的,则出栈。"( )"除外
while (!char_stack.isEmpty() && !c.isPrioritizeThen(char_stack.peek())
&& !char_stack.peek().value.equals("(")) {
rpn_expression.append(char_stack.pop().value);
rpn_expression.append(" ");
}
// 当前运算符入栈
char_stack.push(c);
break;
case ")":
// 依次输出"("前所有的运算符
if (left_bracket_cnt != 0) {
while (!char_stack.peek().value.equals("(")) {
rpn_expression.append(char_stack.pop().value);
rpn_expression.append(" ");
}
// 移除栈顶的"("
char_stack.pop();
}
break;
default:
break;
}
}
} catch (NumberFormatException e) {
throw new NumberFormatException("不支持的运算符或数字");
} catch (Exception e) {
throw new Exception("表达式格式不正确");
}
} else {
temp.append(s);
}
}
return rpn_expression.toString();
}
/**
* 判断字符串是否为标准四则运算符 +、-、*(×)、/(÷)
*
* @param str
* @return
*/
private static String isOperationalCharacter(String str) {
initOperCharMap();
str = str.trim();
if (OPER_CHAR_MAP.containsKey(str)) {
return str;
} else {
return null;
}
}
/**
* 计算后缀表达式
*
* @return
*/
private static double calRPN(String rpn_expression) {
String[] characters = rpn_expression.split(" ");
Stack<Double> char_stack = new Stack<>();
for (int i = 0; i < characters.length; i++) {
if (isOperationalCharacter(characters[i]) == null) {
char_stack.push(Double.parseDouble(characters[i]));
} else {
double first = char_stack.pop();
double second = char_stack.pop();
switch (characters[i]) {
case "*":
char_stack.push(first * second);
break;
case "/":
char_stack.push(second / first);
break;
case "+":
char_stack.push(first + second);
break;
case "-":
char_stack.push(second - first);
break;
default:
break;
}
}
}
return char_stack.pop();
}
/**
* 四则运算符
*
* @author kevingcang
*
*/
static class Character {
/**
* 值
*/
private String value;
/**
* 优先级
*/
private int priority;
public Character(String value, int priority) {
super();
this.value = value;
this.priority = priority;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
public boolean isPrioritizeThen(Character chr) {
if (this.priority > chr.priority) {
return true;
} else {
return false;
}
}
}
public static void main(String[] args) {
String str = "(1+2*3/4+5+(6*7)/8)";
try {
System.out.println(StackDemo2.calMathExpression(str));
} catch (Exception e) {
e.printStackTrace();
}
}
}
四则表达式转后缀表达式、后缀表达式的计算主要借助栈来实现。原表达式为:(1+2*3/4+5+(6*7)/8) 转换为后缀表达式后 1 2 3 * 4 / + 5 + 6 7 * 8 / + 计算结果为:12.75。为方便数据用的double类型。