Discuss / Java / 学习笔记-进阶练习2

学习笔记-进阶练习2

Topic source

a'ゞ抉择

#1 Created at ... [Delete] [Delete and Lock User]
import java.util.*;

enum Operator {
    ADD("+", 1), SUBTRACT("-", 1),
    MULTIPLY("*", 2), DIVIDE("/", 2),
    LEFT_BRACKET("(", 3), RIGHT_BRACKET(")", 3);
    String value;
    int priority;

    Operator(String value, int priority) {
        this.value = value;
        this.priority = priority;
    }

    /**
     * 比较两个符号的优先级
     *
     * @return c1的优先级是否比c2的高,高则返回正数,等于返回0,小于返回负数
     */
    public static int cmp(String c1, String c2) {
        int p1 = 0;
        int p2 = 0;
        for (Operator o : Operator.values()) {
            if (Objects.equals(o.value, c1)) {
                p1 = o.priority;
            }
            if (Objects.equals(o.value, c2)) {
                p2 = o.priority;
            }
        }

        return p1 - p2;
    }

    /**
     * 枚举出来的才视为运算符,用于扩展
     *
     * @return true 表示非运算符, false 表示是运算符,符号在枚举类型中
     */
    public static boolean isNotOperate(String c) {
        for (Operator o : Operator.values()) {
            if (Objects.equals(o.value, c)) {
                return false;
            }
        }
        return true;
    }

}

public class Test {
    public static void main(String[] args) {
        String exp = "6*(x+(2+3)*y+3)";
        SuffixExpression se = compile(exp);
        Map<String, Integer> env = Map.of("x", 3, "y", 4);
        int result = se.execute(env);
        System.out.println(exp + " = " + result + " " + (result == 6 * (3 + (2 + 3) * 4 + 3) ? "✓" : "✗"));
    }

    static SuffixExpression compile(String exp) {
        // --- 实例 1个列表 和 1个堆栈 用来存储运算符和输出结果
        List<String> arrStrOpt = new ArrayList<>();
        Deque<String> stackOperate = new LinkedList<>();

        // 记录当前的非操作符字符 用于后续拼接成完整的数值
        // 适用于多位的数值,例如:123
        StringBuilder strValue = new StringBuilder();

        // --- 遍历传入的表达式
        for (int i = 0; i < exp.length(); i++) {
            String strTempChar = String.valueOf(exp.charAt(i));
            // 为空跳过
            if (strTempChar.equals(" "))
                continue;

            // --- 数值的判断
            // 非操作符 记录当前字符
            if (Operator.isNotOperate(strTempChar)) {
                strValue.append(strTempChar);
                continue;
            }
            // 到操作符了 说明前面的数值类字符已经遍历完了
            // 拼接为一个完整数值 并添加到输出结果
            if (strValue.length() > 0) {
                arrStrOpt.add(strValue.toString());
                strValue.delete(0, strValue.length());
            }

            // --- 操作符的判断
            // 规则1:右括号 ")" 用于强制在遇到右括号时将栈中的操作符弹出,直到遇到相应的左括号为止。
            if (strTempChar.equals(Operator.RIGHT_BRACKET.value)) {
                while (!(stackOperate.isEmpty() || stackOperate.peek().equals(Operator.LEFT_BRACKET.value))) {
                    arrStrOpt.add(stackOperate.pop());
                }
                // 输入无误的情况下 肯定会在"("的时候停下 所以这边直接把"("弹掉就好了
                stackOperate.pop();
            }
            // 规则2:如果栈为空,或者栈顶为左括号"(",那么遇到的操作符直接入栈。
            // 规则3:如果遇到的操作符优先级大于栈顶操作符的优先级,那么遇到的操作符入栈。
            else if (stackOperate.isEmpty() || stackOperate.peek().equals(Operator.LEFT_BRACKET.value)
                    || Operator.cmp(strTempChar, stackOperate.peek()) > 0
            ) {
                stackOperate.push(strTempChar);
            }
            // 规则4:如果遇到的操作符优先级小于等于栈顶操作符的优先级,那么将栈顶的操作符弹出并添加到逆波兰表达式中
            // 然后继续比较新的栈顶操作符,直到满足上述条件后再将遇到的操作符入栈。
            else if (Operator.cmp(strTempChar, stackOperate.peek()) <= 0) {
                while (!(stackOperate.isEmpty() || stackOperate.peek().equals(Operator.LEFT_BRACKET.value)
                        || Operator.cmp(strTempChar, stackOperate.peek()) > 0)
                ) {
                    arrStrOpt.add(stackOperate.pop());
                }
                stackOperate.push(strTempChar);
            }

            //System.out.println(stackOperate);
        }

        // --- 遍历完毕
        // 1. 拼接最后的数值
        // 2. 出栈剩余的所有操作符
        if (strValue.length() > 0) {
            arrStrOpt.add(strValue.toString());
            strValue.delete(0, strValue.length());
        }
        while (!stackOperate.isEmpty()) {
            arrStrOpt.add(stackOperate.pop());
        }

        // System.out.println(arrStrOpt);
        return new SuffixExpression(arrStrOpt);
    }
}

class SuffixExpression {
    // final 只是引用不可变 所以设置为这个没有关系
    // 因为数组类是可以直接修改内部的
    private final List<String> m_arrOpt;
    private final Deque<Integer> m_stack = new LinkedList<>();

    SuffixExpression(List<String> arrOpt) {
        this.m_arrOpt = arrOpt;
    }

    int execute(Map<String, Integer> env) {
        for (String strChar : m_arrOpt) {
            if (Operator.isNotOperate(strChar)) {
                switch (strChar) {
                    case "x" -> m_stack.push(env.get("x"));
                    case "y" -> m_stack.push(env.get("y"));
                    default -> m_stack.push(Integer.parseInt(strChar));
                }
            } else {
                int iValue2 = m_stack.pop(); // 堆栈是先进后出 所以这边iValue2要在前面
                int iValue = m_stack.pop();
                int res = switch (strChar) {
                    case "+" -> (iValue + iValue2);
                    case "-" -> (iValue - iValue2);
                    case "*" -> (iValue * iValue2);
                    case "/" -> (iValue / iValue2);
                    default -> 0;
                };
                m_stack.push(res);
            }
        }

        return m_stack.pop();
    }
}

  • 1

Reply