中缀表达式转后缀表达式(逆波兰式)及其运算(多位整数的四则运算)-Java

/**
 * 中缀表达式如何转后缀表达式?
 * 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("运算符错误");
        };
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值