我们在数学中常见的计算式,例如9 + ( 3 - 1 ) * 3 + 10 / 2。表达式中涉及到了多个运算符,而运算符之间是有优先级的,而计算器没法理解,因为计算机只会按照输入的运算符一个一个的进行计算。
为了避开运算优先级的问题,计算机常采用前、后缀表达式来处理。那么前、后缀表达式为什么能避开优先级的问题,接着看正文。
一、定义
1.1、中缀表达式
定义:一个通用的算术或逻辑公式表示方法, 操作符是以中缀形式处于操作数的中间(例:3 + 4),中缀表达式是人们常用的算术表示方法。
9 + ( 3 - 1 ) * 3 + 10 / 2
1.2、后缀表达式
后缀表达式,又称逆波兰式,指的是不包含括号,运算符放在两个运算对象的后面(例:3 4 +),所有的计算按运算符出现的顺序,严格从左向右进行(不再考虑运算符的优先规则)
9 3 1 - 3 * + 10 2 / +
1.3、前缀表达式
前缀表达式就是不含括号的算术表达式,而且它是将运算符写在前面(例:+ 3 4), 操作数写在后面的表达式,也称为“波兰式”
二、中缀表达式转后缀表达式
这里我们需要用到栈的结构,转换规则是:
数字输出,运算符进栈,括号匹配出栈,栈顶优先级低出栈
以“9 + ( 3 - 1 ) * 3 + 10 / 2”为例
2.1、数字9输出
数字直接输出

2.2、运算符+(进栈
遇到运算符进栈(要求栈顶优先级高)

2.3、括号匹配出栈
遇到")“,输出”( -"

2.4、栈顶优先级低出栈
要添加的*优先级高,需要先清空栈

2.5、清空栈
清空剩余的+ /

三、后缀表达式的计算
后缀表达式运算规则是碰到数字入栈,碰到运算符则取出栈中的两个元素做运算,并将结果再次入栈
仍以“9 3 1 - 3 * + 10 2 / +”为例
步骤1:9
步骤2:9 3
步骤3:9 3 1
这时候遇到"-",计算3-1
步骤4:9 2
步骤5:9 2 3
这时候遇到"x",计算2x3
步骤6:9 6
这时候遇到"+",计算9+6
步骤7:15
步骤8:15 10
步骤9:15 10 2
这时候遇到"/",计算10/2
步骤10:15 5
这时候遇到"+",计算15+5
步骤11:20
四、java运行demo
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Stack;
import java.util.regex.Pattern;
public class Test {
public static void main(String[] args) {
/**
* 中缀表达式 9 + ( 3 - 1 ) * 3 + 10 / 2 = 20
* 后缀表达式 9 3 1 - 3 * + 10 2 / +
*/
String[] infixExpression = {"9", "+", "(", "3", "-", "1", ")", "*", "3", "+", "10", "/", "2"};
String[] postfixExpression = convert(infixExpression);
// 打印转换的后缀表达式
System.out.print("后缀表达式:");
for (int i = 0; i < postfixExpression.length; i++) {
System.out.print(postfixExpression[i] + " ");
}
System.out.println();
// 打印后缀表达式的计算结果
String result = calculateResult(postfixExpression);
System.out.println("后缀表达式计算结果:" + result);
}
// 中缀表达式转后缀表达式
// 数字输出,运算符进栈,括号匹配出栈,栈顶优先级低出栈
private static String[] convert(String[] expressArr) {
Stack<String> stack = new Stack<>();
List<String> result = new ArrayList<>();
for (int i = 0; i < expressArr.length; i++) {
Pattern patternNumber = Pattern.compile("([1-9]\\d*\\.?\\d*)|(0\\.\\d*[1-9])");
if (patternNumber.matcher(expressArr[i]).matches()) {
// 数字输出
result.add(expressArr[i]);
} else if (Arrays.asList(new String[]{"+", "-", "*", "/", "(", ")"}).contains(expressArr[i])) {
if (expressArr[i].equals(")")) {
// 括号匹配出栈
while (!stack.peek().equals("(")) {
result.add(stack.pop());
}
stack.pop();
} else {
boolean a = Arrays.asList(new String[]{"+", "-"}).contains(expressArr[i]);
boolean b = !stack.isEmpty() && Arrays.asList(new String[]{"*", "/"}).contains(stack.peek());
if (a && b) {
// 栈顶优先级低出栈
while (!stack.isEmpty()) {
result.add(stack.pop());
}
stack.push(expressArr[i]);
} else {
// 运算符进栈
stack.push(expressArr[i]);
}
}
}
}
// 剩余出栈
while (!stack.isEmpty()) {
result.add(stack.pop());
}
return result.toArray(new String[0]);
}
// 计算后缀表达式结果
private static String calculateResult(String[] expressArr) {
Stack<String> stack = new Stack<>();
for (int i = 0; i < expressArr.length; i++) {
switch (expressArr[i]) {
case "+":
String A = stack.pop();
String B = stack.pop();
stack.push((Double.parseDouble(B) + Double.parseDouble(A)) + "");
break;
case "-":
A = stack.pop();
B = stack.pop();
stack.push((Double.parseDouble(B) - Double.parseDouble(A)) + "");
break;
case "*":
A = stack.pop();
B = stack.pop();
stack.push((Double.parseDouble(B) * Double.parseDouble(A)) + "");
break;
case "/":
A = stack.pop();
B = stack.pop();
stack.push((Double.parseDouble(B) / Double.parseDouble(A)) + "");
break;
default:
stack.push(expressArr[i]);
break;
}
}
return stack.pop();
}
}
运算结果
