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位的数值和变量值都可以支持

posted @ 2025-06-17 10:41  听歌戴耳机  阅读(13)  评论(0)    收藏  举报