zoukankan      html  css  js  c++  java
  • 將中綴運算式轉換為逆波蘭運算式並計算結果

    看了一下我的播客, 自從加入培訓班後就沒怎麼更新了, 主要還是覺得代碼水準有所提升, 之前寫的一些非常基礎的代碼已經變的沒有太大價值了.

    繼續寫這一類代碼, 用處也不大, 以後可能會上一些品質比較高的代碼. 最起碼對我而言還是有一定難度的.

    這裡上一段逆波蘭運算式的代碼.

    需求是這樣的: 將String math = "12.8 + (2 - 3.55)*4+10/5.0"這個中綴表達式的字符串轉換為逆波蘭表達式(後綴表達式), 並計算出結果.

    轉換后的逆波蘭表達式應該是這樣的: 12.8, 2, 3.55, -, 4, *, +, 10, 5.0, /, +

    這個代碼涉及到了集合, 和棧的一些基本操作. 這裏就不詳細記錄了. 主要還是記錄一下大體的思路

    思路如下:

        1, 定義運算符的優先級, 並將優先級計算方法寫出來.

        2, 掃描中綴表達式,順序進行判斷, 在判斷的過程中用棧存儲計算結果, 用一個集合存儲後綴表達式.

        3, 計算的邏輯是這樣的: 從左往右掃描, 如果第一個拿到的不是括號或者數字, 抛異常, 掃描第一個數字, 并且掃描後面的並判斷,

         如果還是數字, 或者小數點, 拿到后做拼接, 直到掃描到運算符停止, 將拼接的結果入棧; 掃描到第一個符號, 直接入棧,再往下,

         遇到左括號也直接入棧, 繼續掃描, 重複上一個邏輯, 直到遇到右括號, 遇到右括號后, 將前面兩個數彈出, 再從符號棧彈出左括號和一個運算符,

         計算后得到一個數, 再次入棧.(這裏要將左右括號丟掉). 如果上一個邏輯中有多個數和多個運算符, 計算運算符的優先級, 根據優先級做彈棧和計算,

           這樣一直掃描計算, 最終棧裏只剩下一個數字時, 就是計算結果. 縂的來説思路就是判斷是數字還是運算符, 運算符計算優先級,

           計算離優先級高的運算符的進棧數字, 重複這個邏輯到全部掃描計算完.

    寫代碼需要注意的是: 思路一定要清晰, 且連貫. 使用循環進行判斷時一定要區分清楚每一個判斷邏輯的進, 出, 終止的條件. 一旦判斷邏輯不正確, 代碼必然出錯.

              切記, 切記

    看過的相關視頻資料的大神或許會説我只是搬磚工, 這一點我沒法反駁, 我也不想分辨什麽, 寫這個博客本來的目的也只是做個筆記, 給自己看看, 順帶復習所學

    開心就好, o(* ̄▽ ̄*)ブ

    package com.stack;
    
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    import java.util.Stack;
    import java.util.regex.Pattern;
    
    public class ReversePolishMultiCalc {
        static final String SYMBOL = "\+|-|\*|/|\(|\)";
        static final String LEFT = "(";
        static final String RIGHT = ")";
        static final String ADD = "+";
        static final String MINUS = "-";
        static final String TIMES = "*";
        static final String DIVISION = "/";
        static final int LEVEL_01 = 1;
        static final int LEVEL_02 = 2;
        static final int LEVEL_HIGH = Integer.MAX_VALUE;
        
        
        static Stack<String> stack = new Stack<>();
        static List<String> data = Collections.synchronizedList(new ArrayList<String>());
        
        /**
         * 去除所有空白字符
         * @param s
         * @return
         */
        public static String replaceAllBlank(String s) {
            //去空白
            return s.replaceAll("\s+", "");
        }
        
        /**
         * 判斷是否是數字
         * @param s
         * @return
         */
        public static boolean isNumber(String s) {
            Pattern pattern = Pattern.compile("^[-\+]?[.\d]*$");
            return pattern.matcher(s).matches();
        }
        
        /**
         * 判斷運算符
         * @param s
         * @return
         */
        public static boolean isSymbol(String s) {
            return s.matches(SYMBOL);
        }
        
        public static int calLevel(String s) {
            if ("+".equals(s) || "-".equals(s)) {
                return LEVEL_01;
            } else if ("*".equals(s) || "/".equals(s)) {
                return LEVEL_02;
            }
            return LEVEL_HIGH;
        }
        
        public static List<String> doMath (String s) throws Exception {
            if (s == null || "".equals(s.trim())) throw new RuntimeException("表達式不能為空");
            if (!isNumber(s.charAt(0)+"")) throw new RuntimeException("數據類型錯誤");
            
            s = replaceAllBlank(s);
            
            String each;
            int start = 0;
            
            for (int i = 0; i < s.length(); i++) {
                if (isSymbol(s.charAt(i) + "")) {
                    each = s.charAt(i) + "";
                    //判斷1
                    if (stack.isEmpty() || LEFT.equals(each)
                            || ((calLevel(each) > calLevel(stack.peek())) && calLevel(each) < LEVEL_HIGH)) {
                        stack.push(each);
                        //判斷2
                    } else if (!stack.isEmpty() && calLevel(each) <= calLevel(stack.peek())) {
                        //棧非空,操作符優先級小於等於棧頂優先級時出棧入集合,直到棧空,或者遇到(,最後操作符入棧
                        while (!stack.isEmpty() && calLevel(each) <= calLevel(stack.peek())) {
                            if (calLevel(stack.peek()) == LEVEL_HIGH) {
                                break;
                            }
                            data.add(stack.pop());
                        }
                        stack.push(each);
                    } else if (RIGHT.equals(each)) {
                        //判斷3
                        while (!stack.isEmpty() && LEVEL_HIGH >= calLevel(stack.peek())) {
                            if (LEVEL_HIGH == calLevel(stack.peek())) {
                                stack.pop();
                                break;
                            }
                            data.add(stack.pop());
                        }
                    }
                    start = i;
                }else if (i == s.length() - 1 || isSymbol(s.charAt(i + 1) + "")) {
                    //!!!
                    each = start == 0 ? s.substring(start, i + 1) : s.substring(start + 1, i + 1);
                    if (isNumber(each)) {
                        data.add(each);
                        continue;
                    }
                    throw new RuntimeException("表達式類型不匹配數字");
                }
            }
            Collections.reverse(stack);
            data.addAll(new ArrayList<>(stack));
            //測試打印後綴表達式
            System.out.println(data);
            return data;
        }
        //算結果
        public static Double doCalc(List<String> list) {
            Double d = 0d;
            if (list == null || list.isEmpty()) {
                return null;
            }
            if (list.size() == 1) {
                System.out.println(list);
                d = Double.valueOf(list.get(0));
                return d;
            }
            ArrayList<String> list1 = new ArrayList<>();
            for (int i = 0; i < list.size(); i++) {
                list1.add(list.get(i));
                if (isSymbol(list.get(i))) {
                    //丟失break會導致運算出錯
                    Double d1 = doTheMath(list.get(i - 2), list.get(i - 1), list.get(i));
                    list1.remove(i);
                    list1.remove(i - 1);
                    list1.set(i - 2, d1 + "");
                    list1.addAll(list.subList(i + 1, list.size()));
                    break;
                }
            }
            doCalc(list1);
            return d;
        }
        
        public static Double doTheMath(String s1, String s2, String symbol) {
    //        System.out.println(s1 + "++"+s2 );
            Double result;
            switch (symbol) {
            case ADD:
                result = Double.valueOf(s1) + Double.valueOf(s2);
                break;
            case MINUS:
                result = Double.valueOf(s1) - Double.valueOf(s2);
                break;
            case TIMES:
                result = Double.valueOf(s1) * Double.valueOf(s2);
                break;
            case DIVISION:
                result = Double.valueOf(s1) / Double.valueOf(s2);
                break;
            default : result = null;
            }
            return result;
        }
        
        public static void main(String[] args) {
            String math = "12.8 + (2 - 3.55)*4+10/5.0";
            try {
                doCalc(doMath(math));
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
  • 相关阅读:
    这是另外一篇
    使用客户端写博客
    vim编码相关配置
    给eclipse装一些插件
    手机型号收集
    解决黑苹果与windows时区不一致
    记录一些在VPS上折腾的东西
    一个获取文件绝对路径的sh
    python批量GBK转UTF-8
    用NDK编译lua库
  • 原文地址:https://www.cnblogs.com/zzzzzpaul/p/11582198.html
Copyright © 2011-2022 走看看