Java学习Stack实践-中缀转后缀
问题
利用Stack把字符串中缀表达式编译为后缀表达式,然后再利用栈执行后缀表达式获得计算结果。
import java.util.*;
public class Main {
public static void main(String[] args) {
String exp = "1 + 2 * (9 - 5)";
SuffixExpression se = compile(exp);
int result = se.execute();
System.out.println(exp + " = " + result + " " + (result == 1 + 2 * (9 - 5) ? "✓" : "✗"));
}
static SuffixExpression compile(String exp) {
// TODO:
return new SuffixExpression();
}
}
class SuffixExpression {
int execute() {
// TODO:
return 0;
}
}
分析
在大模型中提问后,了解到中缀转后缀会用到经典的调度场算法,算法思路大概是:
1.初始化数据结构
- 建立一个空栈(用于存储操作符)和一个空队列(用于存储后缀表达式)。
- 定义操作符优先级(如 () 优先级最高,其次是 */,最后是 +-)。
2.遍历中缀表达式
- 对每个元素执行以下操作:
- 操作数:直接加入队列。
- 左括号 (:入栈。
- 右括号 ):将栈中元素弹出并加入队列,直到遇到左括号(左括号弹出但不加入队列)。
- 操作符:
当栈不为空且栈顶操作符优先级 大于等于 当前操作符时,弹出栈顶操作符并加入队列,重复此过程;最后将当前操作符入栈。
3.处理剩余操作符
- 遍历结束后,将栈中剩余的操作符依次弹出并加入队列。
后缀表达式通过栈求值,大概思路是:
1.遍历后缀表达式,如果元素是数字就入栈。
2.如果元素是操作符(+-*/)就取栈顶的两个数字进行计算,并把计算结果入栈,得注意计算先后关系。
3.最后栈中剩余一个值时,就是表达式结果。
解
import java.util.*;
public class test {
public static void main(String[] args) {
String exp = "1 + 2 * (9 - 5)";
SuffixExpression se = compile(exp); //后缀表达式
int result = se.execute(); //栈执行
int expected = 1 + 2 * (9 - 5);
System.out.println(exp + " = " + result + " " + ((result == expected) ? "正确" : "错误"));//对比结果
}
static SuffixExpression compile(String exp) {
//经典的调度场算法 中缀转后缀
StringBuilder postfix = new StringBuilder();
Deque<Character> stack = new ArrayDeque<>();
for (char c : exp.toCharArray()) {
if (c == ' ') {
continue; // 跳过空格
}
if (Character.isDigit(c)) {
postfix.append(c);
} else if (c == '(') {
stack.push(c);
} else if (c == ')') {
while (!stack.isEmpty() && stack.peek() != '(') {
postfix.append(stack.pop());
}
stack.pop(); // 弹出左括号
} else if (isOperator(c)) {
while (!stack.isEmpty() && stack.peek() != '(' && priority(stack.peek()) >= priority(c)) {
postfix.append(stack.pop());
}
stack.push(c);
}
}
while (!stack.isEmpty()) {
postfix.append(stack.pop());
}
return new SuffixExpression(postfix.toString());
}
static boolean isOperator(char c) {
return c == '+' || c == '-' || c == '*' || c == '/';
}
static int priority(char op) {
switch (op) {
case '+':
case '-':
return 1;
case '*':
case '/':
return 2;
default:
return 0;
}
}
}
class SuffixExpression {
String exp;
SuffixExpression(String exp){
this.exp = exp;
}
int execute() {
Deque<Integer> stack = new ArrayDeque<>();
for(char c : exp.toCharArray()){
if(c == ' ') {
continue; // 跳过空格
}
if(test.isOperator(c)){
int b = stack.pop();
int a = stack.pop();
switch(c){
case '+':
stack.push(a + b);
break;
case '-':
stack.push(a - b);
break;
case '*':
stack.push(a * b);
break;
case '/':
stack.push(a / b);
break;
}
} else if(Character.isDigit(c)){
stack.push(c - '0');
}
}
return stack.pop();
}
}
后记
用了大模型来解决时,大模型有了一种更加完善的思路,就是先进行Tokenize,而不是直接用char来处理原来的中缀表达式
static List<String> tokenize(String exp) {
List<String> tokens = new ArrayList<>();
StringBuilder sb = new StringBuilder();
for (char c : exp.toCharArray()) {
if (Character.isWhitespace(c)) continue;
if (Character.isLetterOrDigit(c)) {
sb.append(c);
} else {
if (sb.length() > 0) {
tokens.add(sb.toString());
sb.setLength(0);
}
tokens.add(String.valueOf(c));
}
}
if (sb.length() > 0) {
tokens.add(sb.toString());
}
return tokens;
}
在转换时,先进行Tokenize,再转换为后缀表达式。这样多于1位的数值和变量值都可以支持

浙公网安备 33010602011771号