java实现中缀表达式转后缀表达式

package com.bigdata.datastructure.stack;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

/**
 * @ description: 中缀表达式转后缀表达式,并计算值
 * @ author: spencer
 * @ date: 2020/10/30 9:21
 */
public class Calculator2 {

    public static void main(String[] args) {

        String expression = "1+((123+3)*4)-15";

        List<String> list = expressionToList(expression);
        System.out.println(list);

        List<String> suffixExpression = parseToSuffixExpression(list);
        System.out.println(suffixExpression);

        int result = calculate(suffixExpression);
        System.out.println(expression + " = " + result);

    }

    /**
     * 根据后缀表达式计算值
     * @param list
     * @return
     */
    public static int calculate(List<String> list){
        Stack<Integer> stack = new Stack<>();
        for (String item : list) {
            if (item.matches("\\d+")){
                stack.push(Integer.parseInt(item));
            } else {
                // 是操作符,取出栈顶元素和次顶元素
                int num2 = stack.pop();
                int num1 = stack.pop();
                int result = 0;
                switch (item){
                    case "+":
                        result = num1 + num2;
                        break;
                    case "-":
                        result = num1 - num2;
                        break;
                    case "*":
                        result = num1 * num2;
                        break;
                    case "/":
                        result = num1 / num2;
                        break;
                    default:
                        break;
                }
                stack.push(result);
            }
        }
        return stack.pop();
    }

    /**
     * 中缀表达式转换为后缀表达式
     * 转换规则:
       1)我们使用一个stack栈结构存储操作符,用一个List结构存储后缀表达式结果
       2)首先读取到数字,直接存入list中
       3)当读取到左括号"("时,直接压栈,当读取到运算符时,分两种情况讨论
         a.当运算符栈为空或者栈顶操作符的优先级小于当前运算符优先级时(如+和-的优先级低于 * 和 /),直接入栈
         b.当运算符不为空时且栈顶操作符的优先级大于或等于当前运算符优先级时,循环执行出栈操作并加入list中,直到遇到优先级小于当前运算符的元素为止。
     循环执行完后再将当前运算符压栈。另外需要注意的是,只有遇到右括号时,左括号才出栈
       4) 当遇到右括号")"时,循环执行出栈操作并加入到list中,直到遇到左括号为止。并将左括号弹出,但不加入list中
       5) 表达式的值读取完后,将操作符栈中的所有元素弹出并加入到list中
      执行完上面步骤后,list中存储的顺序即为我们转换后的后缀表达式的结果
     * @param list
     * @return
     */
    public static List<String> parseToSuffixExpression(List<String> list){
        Stack<String> operStack = new Stack<>();
        ArrayList<String> suffixList = new ArrayList<>();
        for (String s : list) {
            if (isOper(s)){
                // 如果符号栈为空,或者符号栈中栈顶元素为左括号,或者当前符号的优先级大于栈顶元素优先级,则直接将符号入栈
                if (operStack.isEmpty() || operStack.peek().equals("(") || priority(s) >= priority(operStack.peek())){
                    operStack.push(s);
                } else {
                    // 如果符号栈不为空,且符号栈中栈顶元素为左括号
                    while (!operStack.isEmpty() && ! "(".equals(operStack.peek())){
                        if (priority(s) < priority(operStack.pop())){
                            suffixList.add(operStack.pop());
                        }
                    }
                    // 循环完成后将当前操作符入符号栈
                    operStack.push(s);
                }
            } else if (isNumber(s)){
                suffixList.add(s);
            } else if (s.equals("(")){
                operStack.push(s);
            } else if (s.equals(")")){
                while (operStack != null){
                    if (operStack.peek().equals("(")){
                        operStack.pop();
                        break;
                    } else {
                        suffixList.add(operStack.pop());
                    }
                }
            } else {
                throw new RuntimeException("有非法字符");
            }
        }
        while (!operStack.isEmpty()){
            suffixList.add(operStack.pop());
        }
        return suffixList;
    }

    /**
     * 将表达式存入list,好遍历
     * @param expression
     * @return
     */
    public static List<String> expressionToList(String expression){
        List<String> list = new ArrayList<>();
        int index = 0;
        do{
            char ch = expression.charAt(index);
            if (ch < 48 || ch > 57){
                index++;
                list.add(ch + "");
            } else if (ch >= 48 && ch <= 57){
                String keepNum = "";
                while (index < expression.length() && expression.charAt(index) >= 48 && expression.charAt(index) <= 57){
                    keepNum += expression.charAt(index);
                    index++;
                }
                list.add(keepNum);
            }
        } while (index < expression.length());

        return list;
    }

    /**
     * 判断是否为符号
     * @param oper
     * @return
     */
    public static boolean isOper(String oper){
        return oper.equals("+") || oper.equals("-") || oper.equals("*") || oper.equals("/");
    }

    /**
     * 判断是否为数字
     * @param num
     * @return
     */
    public static boolean isNumber(String num){
        return num.matches("\\d+");
    }

    /**
     * 判断符号的优先级
     * @param oper
     * @return
     */
    public static int priority(String oper){
        if (oper == "*" || oper == "/"){
            return 1;
        } else if ((oper == "+" || oper == "-")){
            return 0;
        } else {
            return -1;
        }
    }
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值