• 6, java数据结构和算法: 栈的应用, 逆波兰计算器, 中缀表达式--> 后缀表达式


    直接上代码:

    public class PolandCalculator {
        //栈的应用:波兰计算器:  即: 输入一个字符串,来计算结果, 比如 1+((2+3)×4)-5 结果为16
        public static void main(String[] args) throws Exception {
            /**
             *  思路:
             *  1: 将 1+((2+3)×4)-5 (这叫中缀表达式,运算符再数字中间), 转换为后缀表达式 (1 2 3 + 4 × + 5 –)
             *  2: 使用栈, 将后缀表达式 , 计算得出结果
             *
             *  因为 后缀表达式, 来计算会变得简单易懂, 不需要那么多的判断, 只需要 数入栈,然后判断运算符, 从栈中pop出二个数,计算,并把结果入栈, 循环往复,得到最终结果
             */
    
            String str = "1+((2+3)*4)-5";
            // 1, 先将 str 字符串变为对应的 中缀表达式 midExpressionList(便于显示)
            List<String> midExpressionList = toMidExpressionList(str);
            System.out.println("前缀表达式为: "+midExpressionList);
            // 2, 将 midExpressionList 转换为 后缀表达式对应的 suffixExpressionList
            List<String> suffixExpressionList = toSuffixExpressionList(midExpressionList);
            System.out.println("后缀表达式为: "+suffixExpressionList);
            // 3, 计算结果
            calculator(suffixExpressionList);
        }
    
        private static List<String> toMidExpressionList(String s) {
            //定义一个List,存放中缀表达式 对应的内容
            List<String> ls = new ArrayList<String>();
            int i = 0; //这时是一个指针,用于遍历 中缀表达式字符串
            String str; // 对多位数的拼接
            char c; // 每遍历到一个字符,就放入到c
            do {
                //如果c是一个非数字,我需要加入到ls
                if((c=s.charAt(i)) < 48 ||  (c=s.charAt(i)) > 57) {
                    ls.add("" + c);
                    i++; //i需要后移
                } else { //如果是一个数,需要考虑多位数
                    str = ""; //先将str 置成"" '0'[48]->'9'[57]
                    while(i < s.length() && (c=s.charAt(i)) >= 48 && (c=s.charAt(i)) <= 57) {
                        str += c;//拼接
                        i++;
                    }
                    ls.add(str);
                }
            }while(i < s.length());
            return ls;//返回
        }
    
        private static List<String> toSuffixExpressionList(List<String> midExpressionList) {
            //1, 定义一个栈 用来存运算符
            Stack<String> cal = new Stack<String>();
            //2, 定义一个list 来做存中间结果和返回,  也可以定义一个栈, 但是用栈的话, 这个转换过程并没有pop操作, 而且还要逆序显示,比较麻烦, 所以用list
            List<String> resList = new ArrayList<String>();
            for (String str : midExpressionList) {
                if(str.matches("\d+")){
                    //是一个或多个数字, 就存入resList
                    resList.add(str);
                }else if (str.equals("(")){
                    //如果是 左括号 , 就加入cal  栈
                    cal.push(str);
                }else if(str.equals(")")){
                    //如果是右括号,  此时需要将cal 栈的运算符号,依次pop,并加入到resList中, 直到遇到"左括号"停止,  最后将"左括号"删除
                    while(! cal.peek().equals("(")){
                        resList.add(cal.pop());
                    }
                    cal.pop();//跳出循环时,已经将"("之前的运算符都存入resList中,  此一步是将"("删除
                }else {
                    //是运算符 +,-,*,/  , 如果是运算符, 如果cal栈为空,直接加入栈,  如果该运算符 优先级小于等于 cal栈顶运算符, 将cal栈中运算符 依次pop,加入到resList中, 知道运算符优先级大于为止
                    while(cal.size() != 0 && operator(str) <= operator(cal.peek())){
                        resList.add(cal.pop());
                    }
                    cal.push(str);
                }
            }
            //最后将 cal栈中的运算符依次弹出加入到resList中
            while(cal.size() != 0){
                resList.add(cal.pop());
            }
            return resList;
        }
    
        private static int operator(String str) {
            if(str.equals("+") || str.equals("-")){
                return 1;
            }
            if(str.equals("*") || str.equals("/")){
                return 2;
            }
            return 0;
        }
    
    
        private static void calculator(List<String> suffixExpressionList) throws Exception {
            Stack<String> stack = new Stack<>();
    
            for (String str : suffixExpressionList) {
                if(str.matches("\d+")){
                    //是数字, 入栈
                    stack.push(str);
                }else{
                    //是运算符, 从栈中pop二个数, 计算,将计算结果存入stack中, 最终stack中的数, 就是计算结果
                    int num2 = Integer.parseInt(stack.pop());
                    int num1 = Integer.parseInt(stack.pop());
                    int res = 0;
    
                    if(str.equals("+")){
                        res = num1 + num2;
                    } else if(str.equals("-")){
                        res = num1 - num2;
                    } else if(str.equals("*")){
                        res = num1 * num2;
                    } else if(str.equals("/")){
                        res = num1 / num2;
                    } else{
                        throw new Exception("没有这个运算符:"+str);
                    }
                    //计算结果  入栈
                    stack.push(String.valueOf(res));
                }
            }
            System.out.println("最终的计算结果为:" + stack.pop());
        }
    
    }
    

    测试结果:

    在测试一个:

  • 相关阅读:
    洛谷P5281 [ZJOI2019] Minimax搜索
    势函数
    Comet OJ [Contest #5] 迫真大游戏
    洛谷P3307 [SDOI2013] 项链
    洛谷P5985 [PA2019] Muzyka pop
    CF1205E Expected Value Again
    review
    CF891E Lust
    线性代数
    洛谷P4607 [SDOI2018] 反回文串
  • 原文地址:https://www.cnblogs.com/lvcai/p/13034463.html
Copyright © 2020-2023  润新知