将中缀表达式转成后缀表达式的工具类:
package Stack.PoLandCaculation;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Stack;
/**
* 将中缀表达式转成后缀表达式的工具类
*/
public class PoLandTransform {
/**
* 一般表达式转后缀表达式
* @param commonExpression 一般表达式
* @return 返回后缀表达式字符串数组,数组每一个元素都是一个数或者运算符
*/
public static ArrayList<String> toPostfixExpression(String commonExpression){
ArrayList<String> list = PoLandTransform.toStringArray(commonExpression);
Stack<String> s1 = new Stack<>();
Stack<String> s2 = new Stack<>();
for (int i = 0; i < list.size(); i++) {//当遍历到数字时,直接压入s2栈
String str = list.get(i);
if (str.matches("\\d+(\\.\\d+)?")) {
s2.push(str);
} else {
//遍历到运算符
//s1为空 或者 遍历到'(' 或者 s1栈顶是'(',运算符直接压入s1栈
if (s1.isEmpty() || str.equals("(") || s1.peek().equals("(")) {
s1.push(str);
} else if (str.equals(")")) {
//当遍历到')'时
//弹出s1中的运算符并压入到s2,直到s1栈顶是'('。最后弹出s1栈顶的'('
while (!s1.peek().equals("(")) s2.push(s1.pop());
s1.pop();
} else {
//当遍历到加减乘除这四个运算符
//先计算当前运算符与s1栈顶运算符的优先级
int priority = PoLandTransform.priority(str, s1.peek());
if (priority == 1) {
//当前运算符比栈顶运算符优先级高
//直接压入s1栈
s1.push(str);
} else {
//比s1栈顶优先级低
//弹出一个s1元素并压入s2,然后当前运算符再次与弹出一次后的s1栈顶元素对比
s2.push(s1.pop());
//回滚索引
i--;
}
}
}
}
//s1栈剩余的运算符依次弹入s2栈中
while (!s1.isEmpty()) s2.push(s1.pop());
//s2栈依次弹出,添加到新的list中
ArrayList<String> newList = new ArrayList<>();
while (!s2.isEmpty()) newList.add(s2.pop());
//将list转置后返回
Collections.reverse(newList);
return newList;
}
/**
* 识别算术表达式,并返回处理好的算式列表
* @param expression 算术表达式
* @return 返回处理好的表达式列表
*/
private static ArrayList<String> toStringArray(String expression){
//表达式匹配到非法字符(匹配到加减乘除和数字以及小数点以外的字符)
if (expression.replaceAll(" ","").matches("[^\\d\\+\\-\\*\\/\\.]")){
throw new RuntimeException("表达式存在非法字符!");
}
ArrayList<String> list = new ArrayList<>();
//将表达式转char数组方便后续处理
char[] exp = expression.replaceAll(" ","").toCharArray();
//定义numStr方便后续拼接多位数数字
String numStr = "";
for (int i = 0; i < exp.length; i++) {
if (exp[i] >= '0' && exp[i] <= '9' || exp[i] == '.'){
//遍历到数字或者小数点,都拼接到numStr
numStr += exp[i];
if (i == exp.length - 1){
//遍历到最后一个数字,记得把最后一个数字也添加到列表list
list.add(numStr);
}
}else if(exp[i] == '+' || exp[i] == '-' || exp[i] == '*' || exp[i] == '/' || exp[i] == '(' || exp[i] == ')'){
//遍历到运算符,先把拼接好的numStr添加进list,然后重置numStr
if (!numStr.isEmpty()) list.add(numStr);
numStr = "";
//把运算符也添加进list
list.add(""+exp[i]);
}
}
return list;
}
/**
* 计算运算符优先级
* @param cur 当前运算符
* @param stackEle 栈顶运算符
* @return 返回0代表当前运算符优先级低或者相等,返回1代表当前运算符优先级高
*/
private static int priority(String cur,String stackEle){
if (stackEle.equals("*") || stackEle.equals("/")){
return (cur.equals("+") || cur.equals("-")) ? 0 : 1;
}
return (cur.equals("+") || cur.equals("-")) ? 0 : 1;
}
}
逆波兰计算器:
package Stack.PoLandCaculation;
import java.util.ArrayList;
import java.util.Stack;
/**
* 逆波兰表达式计算器
*/
public class PoLandCaculation {
/**
* 将一般算式转换成逆波兰表达式后返回算式计算结果
* @param expression 一般算式
* @return 返回计算结果
*/
public static Double poLandCaculate(String expression){
//获取后缀表达式
ArrayList<String> postfixList = PoLandTransform.toPostfixExpression(expression);
Stack<Double> stack =new Stack<>();
postfixList.forEach(str ->{
//遍历到数字直接入栈
if (str.matches("\\d+(\\.\\d+)?")){
stack.push(Double.parseDouble(str));
}else {
//遍历到运算符
//栈顶弹出两个元素,与当前运算符计算后重新入栈
try {
Double result = PoLandCaculation.calculate(stack.pop(), stack.pop(), str);
stack.push(result);
}catch (ArithmeticException e){
throw new ArithmeticException("出现算术异常!");
}catch (RuntimeException e){
throw new RuntimeException(e.getMessage());
}
}
});
//栈中最后剩下的元素就是计算结果,返回结果
return stack.pop();
}
/**
* 根据运算符进行计算并返回结果
* @param num1
* @param num2
* @param operator
* @return
* @throws RuntimeException
*/
private static Double calculate(Double num1,Double num2,String operator) throws RuntimeException{
return switch (operator){
case "+"-> num2+num1;
case "-"-> num2-num1;
case "*"-> num2*num1;
case "/"-> num2/num1;
default -> throw new RuntimeException("未知异常");
};
}
}
测试代码:
package Stack.PoLandCaculation;
import java.util.Scanner;
public class PoLandCaculationTest {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
while (true) {
System.out.println("--------------------------------------------------------------------------------------");
System.out.println("[输入e退出程序]");
System.out.println("请输入计算表达式(支持小数运算、多位数运算、小括号运算):");
System.out.println("--------------------------------------------------------------------------------------");
String expression = scan.next();
if (expression.equalsIgnoreCase("e")) return;
Long startTime = System.currentTimeMillis();
Double result = null;
try {
result = PoLandCaculation.poLandCaculate(expression);
} catch (ArithmeticException e) {
System.out.println(e.getMessage());
}catch (Exception e){
e.printStackTrace();
}
Long endTime = System.currentTimeMillis();
System.out.println("计算结果为:["+result+"]");
System.out.println("本次计算用时:"+ (endTime-startTime) +" ms");
}
}
}
测试图: