逆波蘭表達式&後綴表達式

概念

  1. 前綴表達式又稱波蘭式,前綴表達式的運算符位於操作數之前。比如:- × + 3 4 5 6
  2. 中綴表達式就是常見的運算表達式,如(3+4)×5-6
  3. 後綴表達式又稱逆波蘭表達式,與前綴表達式相似,只是運算符位於操作數之後,比如:3 4 + 5 × 6 -

人類最熟悉的一種表達式1+2,(1+2)3,3+42+4等都是中綴表示法。對於人們來說,也是最直觀的一種求值方式,先算括號裏的,然後算乘除,最後算加減,但是,計算機處理中綴表達式卻並不方便。

我們先看一個例子 (3+4)× 5 - 6  後綴表達式3 4 + 5 × 6 -的計算

  1. 從左至右掃描,將3和4壓入堆棧;
  2. 遇到+運算符,因此彈出4和3(4爲棧頂元素,3爲次頂元素,注意與前綴表達式做比較),計算出3+4的值,得7,再將7入棧;
  3. 將5入棧;
  4. 接下來是×運算符,因此彈出5和7,計算出7×5=35,將35入棧;
  5. 將6入棧;
  6. 最後是-運算符,計算出35-6的值,即29,由此得出最終結果。

中綴表達式轉換爲後綴表達式

1.數字直接入隊列
2.運算符要與棧頂元素比較
 ①棧爲空直接入棧
 ②運算符優先級大於棧頂元素優先級則直接入棧
 ③小於或等於則出棧入列,再與棧頂元素進行比較,直到運算符優先級小於棧頂元
    素優先級後,操作符再入棧
3.操作符是 ( 則無條件入棧
4.操作符爲 ),則依次出棧入列,直到匹配到第一個“(”爲止,此操作符直接捨棄,“(”直接出棧捨棄

 

public class SuffixAlgorithm {

    private static char LEFT_BRACKET = Operator.LEFT_BRACKET.value;
    private static char RIGHT_BRACKET = Operator.RIGHT_BRACKET.value;


    private static void rpn(Stack<Character> operators, Stack output, String exp){
        char[] chars = exp.toCharArray();
        int len = chars.length;
        int bracket = 0; // operators中的左括號的數量

        for (int i = 0; i < len; ) {
            int pre = i;//處理開始下標
            boolean digital = Boolean.FALSE; //是否爲數字(只要不是運算符,都是數字),用於截取字符串
            while (i < len && !Operator.isOperator(chars[i])) {
                i++;
                digital = Boolean.TRUE;
            }

            if (digital) {//如果是數字,直接壓入output
                output.push(exp.substring(pre, i));
            }else{
                char o = chars[i++];

                if (o == LEFT_BRACKET){//左括號直接壓入output
                    operators.push(o);
                    bracket++;
                    continue;
                }

                if(o == RIGHT_BRACKET){//是右括號

                    if(bracket < 1){
                        throw new IllegalArgumentException("can't find '('");
                    }
                    //將operators棧頂彈出壓入output直到左括號
                    while (!operators.empty()) {
                        char top = operators.pop();
                        if (top == LEFT_BRACKET) {
                            break;
                        }
                        output.push(top);
                    }
                    bracket--;
                    continue;
                }

                char p;
                while (!operators.empty()
                        && ( p = operators.peek()) != LEFT_BRACKET
                        && Operator.cmp(o, p) <= 0){
                    output.push(operators.pop());
                }
                operators.push(o);
            }
        }
        while (!operators.empty()){
            output.push(operators.pop());
        }
    }

    public static void main(String[] args) {
        System.out.println(rpn("a*(b-c*d)+e-f/g*(h+i*j-k)"));
        System.out.println("a,b,c,d,*,-,*,e,+,f,g,/,h,i,j,*,+,k,-,*,-");
    }

    public static String rpn(String exp){
        Stack<Character> operators = new Stack<>();
        Stack<Character> output = new Stack();
        rpn(operators, output, exp);
        String str = "";
        for(int i=0; i<output.size();i++){
           str += String.valueOf(output.get(i));
        }
        return str;
    }

    static enum Operator {
        ADD('+', 1), SUBTRACT('-', 1),
        MULTIPLY('*', 2), DIVIDE('/', 2),
        LEFT_BRACKET('(', 3), RIGHT_BRACKET(')', 3);

        char value;
        int priority;

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

        /**
         * 比較兩個符號的優先級
         *
         * @param c1
         * @param c2
         * @return c1的優先級是否比c2的高,高則返回正數,等於返回0,小於返回負數
         */
        public static int cmp(char c1, char c2) {
            int p1 = 0;
            int p2 = 0;
            for (Operator o : Operator.values()) {
                if (o.value == c1) {
                    p1 = o.priority;
                }
                if (o.value == c2) {
                    p2 = o.priority;
                }
            }
            return p1 - p2;
        }

        /**
         * 枚舉出來的才視爲運算符,用於擴展
         *
         * @param c
         * @return
         */
        public static boolean isOperator(char c) {
            for (Operator o : Operator.values()) {
                if (o.value == c) {
                    return true;
                }
            }
            return false;
        }
        
         public static Operator findOperator(char c){
            for (Operator o : Operator.values()) {
                if (o.value == c) {
                    return o;
                }
            }
            return null;
        }
    }
}


 



 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章