/**
* 中缀表达式如何转后缀表达式?
* 1.从左到右扫描表达式
* 1.1 如果是数字,直接入表达式栈
* 1.2 如果是符号:
* 1.2.1 符号栈为空、符号栈栈顶为左括号,直接入栈
* 1.2.2 符号栈不为空,栈顶符号优先级小于待入栈符号,那么直接入栈
* 1.2.3 符号栈不为空,并且符号栈栈顶符号优先级>=这个待入栈符号,那么将栈顶符号出栈到表达式栈,持续出栈到栈顶符号优先级小于这个代入栈符号,或者遇到左括号
* 1.3 扫描到括号
* 1.3.1 如果是左括号,直接入符号栈
* 1.3.2 如果是右括号,依次弹出符号栈的符号到表达式栈,直到遇到左括号,此时需要丢弃这一对左右括号
* 2.扫描完毕
* 3.将符号栈中未出栈的元素依次出栈并压入表达式栈中
* 4.表达式栈中的元素依次出栈,出栈的逆序结果就是后缀表达式
*
* switch语句使用JDK17特性(14及其以上都可以)
* 本代码仅支持多位整数的四则运算(包含括号),未做兼容处理,需按照格式来输入
* 注释中的方法一是自己想的,方法二为韩顺平的代码
* 本代码中,中缀表达式先转为List集合,为了方便取出每个字符
* 然后依次将List集合的元素,配合符号栈和表达式List集合,分别压栈出栈和add到集合,避免了后续对表达式栈出栈结果的逆序
*/
public class PolandNotation {
public static void main(String[] args) {
// 完成中缀表达式转后缀表达式的功能
// String expression = "1+((2+3)*4)-5";
String expression = "9+(3+1*2-1*4+1)+2";
// String expression = "10+(2+3)*(10-5)";
List<String> infixExpressionList = toInfixExpressionList(expression);
System.out.println(infixExpressionList);
List<String> parsedSuffixExpressionList = parseSuffixExpressionList(infixExpressionList);
System.out.println(parsedSuffixExpressionList);
int calculate = calculate(parsedSuffixExpressionList);
System.out.println(calculate);
// 逆波兰表达式(后缀表达式)的计算
// 先定义一个逆波兰表达式
// String suffixExpression = "30 4 + 5 * 6 -";
// String suffixExpression = "4 5 * 8 - 60 + 8 2 / +";
// String suffixExpression = "9 3 1 2 * 1 4 * 1 + - + 2 1 +";
// // 将表达式放到ArrayList中
// // 再将ArrayList传递给方法,然后遍历它,配合栈进行计算
// List<String> rpnList = getListString(suffixExpression);
// System.out.println(rpnList);
// int calculate = calculate(rpnList);
// System.out.println(calculate);
}
// 将一个逆波兰表达式,依次将数据和运算符放入ArrayList中
public static List<String> getListString(String suffixExpression) {
// 分割suffixExpression
String[] split = suffixExpression.split(" ");
return new ArrayList<>(Arrays.asList(split));
}
// 完成对逆波兰表达式的运算
public static int calculate(List<String> ls) {
// 创建一个栈,一个栈即可
Stack<String> stack = new Stack<>();
// 遍历list集合,每当遇到运算符,就从栈中取出两个值进行计算,否则压入栈中
for (String ele : ls) {
if (ele.matches("\\d+")) {
stack.push(ele);
} else {
int num1 = Integer.parseInt(stack.pop());
int num2 = Integer.parseInt(stack.pop());
int res = switch (ele) {
case "+" -> num2 + num1;
case "-" -> num2 - num1;
case "*" -> num2 * num1;
case "/" -> num2 / num1;
default -> throw new RuntimeException("运算符错误");
};
stack.push(String.valueOf(res));
}
}
return Integer.parseInt(stack.pop());
}
// 将中缀表达式转换为List
public static List<String> toInfixExpressionList(String s) {
// 定义一个List,存放中缀表达式
List<String> list = new ArrayList<String>();
int index = 0;
StringBuilder str; // 多位数拼接使用
while (index < s.length()) {
// 如果是运算符,就添加到数组
if (s.charAt(index) < 48 || s.charAt(index) > 57) {
list.add(s.charAt(index) + "");
index++;
} else {
// 方法一:对前一位进行判断
// 如果是数字,就需要判断index的位置
if (index == 0) {
list.add(s.charAt(index) + "");
} else if (s.charAt(index - 1) >= 48 && s.charAt(index - 1) <= 57) {
// 如果上一位是数字,就去判断它的前一位是不是也是数字,如果也是数字,说明他们应该拼接
String value = list.get(list.size() - 1);
list.remove(list.size() - 1);
list.add(value + s.charAt(index));
} else {
// 如果上一位不是数字,那么直接加入集合
list.add(s.charAt(index) + "");
}
index++;
// 方法二:持续取值,直到遇到运算符
// str = new StringBuilder();
// while (index < s.length() && s.charAt(index) >= 48 && s.charAt(index) <= 57) {
// str.append(s.charAt(index));
// index++;
// }
// list.add(str + "");
}
}
return list;
}
// 将中缀表达式转换为后缀表达式
public static List<String> parseSuffixExpressionList(List<String> ls) {
Stack<String> s1 = new Stack<>();
List<String> s2 = new ArrayList<String>();
for (String item : ls) {
// 如果是数字,直接存进list
if (item.matches("\\d+")) {
s2.add(item);
} else if (item.equals("(")) {
s1.push(item);
} else if (item.equals(")")) {
// 弹出括号内的所有符号,直到遇到左括号
while (!s1.peek().equals("(")) {
s2.add(s1.pop());
}
// 弹出左括号
s1.pop();
} else {
// 方法一
// 处理优先级问题(待入栈符号优先级如果小于或者等于栈顶元素的优先级,
// 就需要对栈中元素进行出栈,如果遇到了更小的优先级,那么就入栈)
// 如果是乘除,那么直接入栈
// 如果是加减,那么栈中元素依次出栈,直到栈空或者遇到左括号(该方法仅适用于加减乘除)
// if (item.equals("+") || item.equals("-")) {
// while (!s1.isEmpty() && !s1.peek().equals("(")) {
// s2.add(s1.pop());
// }
// }
// s1.push(item);
// 方法二:添加一个Operation类去处理优先级(拓展性更好)
// 如果当前栈顶的运算符优先级大于待入栈的优先级,那么就开始对栈中元素出栈
try {
while (!s1.isEmpty() && Operation.getValue(s1.peek()) >= Operation.getValue(item)) {
s2.add(s1.pop());
}
s1.push(item);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
while (!s1.isEmpty()) {
s2.add(s1.pop());
}
return s2;
}
}
class Operation {
private static int ADD = 1;
private static int SUB = 1;
private static int MUL = 2;
private static int DIV = 2;
private static int leftBracket = 0;
public static int getValue(String operation) {
return switch (operation) {
case "+" -> ADD;
case "-" -> SUB;
case "*" -> MUL;
case "/" -> DIV;
case "(" -> leftBracket;
default -> throw new RuntimeException("运算符错误");
};
}
}