java棧應用之表示式求值
阿新 • • 發佈:2018-11-27
package stack.demo; import java.io.IOException; import java.util.Scanner; import java.util.Stack; /** * 表示式求值 算符優先法 * 3*(5-2)# #在這裡表示結尾 * * 思路: * 使用兩個棧,分別是運算元棧 儲存數字 和操作符棧 儲存運算子 * 讀入表示式時 * 如果是運算元 則入運算元棧 * 如果是運算子 則入操作符棧 * 當運算子入棧時,和操作符棧棧頂元素比較優先順序 * 如果優先順序比棧頂元素高,則入棧,並接收下一個字元 * 如果和棧頂元素相同,則脫括號 並接收下一個字元 ( 因為相同只有( )括號) * 如果小於棧頂元素優先順序,則操作數出棧,操作符出棧 並計算運算結果再入棧 * * 關鍵點:迴圈的退出條件 直到運算全部結束,即當前棧頂元素和讀入的操作符均為# * * 例子: * 3*(5-2)# * * 算符優先順序: * + -按順序先後,先來優先順序大於後來的,即從左到右依次計算 * * / 優先順序大於+ - , 與* /比較則 先來的優先順序大於後來的 * + - * / 優先順序均大於( 小於) */ public class EvaluateExpression { private static Stack<Character> stackOPR = new Stack<>(); //操作符棧 private static Stack<Integer> stackOPN = new Stack<>();//運算元棧 public static void main(String[] args) throws IOException { char c = (char) System.in.read(); stackOPR.push('#'); while (c != '#' || stackOPR.peek() != '#') { if (isOPN(c)) { //判斷是否是運算元 //是 則入運算元棧 ,讀入下一個 stackOPN.push(c-48); //asc碼 '0'轉為int是48 A是65 a是97 c = (char) System.in.read(); } else { switch (isPrior(c)) { case '>': //優先順序比棧頂元素大 ,則入棧,並接收下一個字元 stackOPR.push(c); c = (char) System.in.read(); break; case '='://優先順序和棧頂元素相同 stackOPR.pop(); //脫去括號 c = (char) System.in.read(); break; case '<': //優先順序比棧頂元素小,則操作數出棧,操作符出棧,運算之後入棧。即意思是優先順序高的先運算 int b = stackOPN.pop();//順序靠後的運算元 int a = stackOPN.pop();//順序靠前的運算元 stackOPN.push(Option(a, b, stackOPR.pop())); break; } } } System.out.println("計算結果為:"+stackOPN.pop()); } //返回和棧頂元素優先順序的比較結果,> 表示優先順序大於棧頂元素 < 表示優先順序小於棧頂元素 =表示優先順序相等 static char isPrior(Character c) { char c2 = stackOPR.peek(); if (c == '+' || c == '-') { //c為後進入的操作符,c2為之前進入的操作符 //如果同為+ - 則c2的優先順序大於c 同理 * /就更不用說了 if (c2 == '+' || c2 == '-' || c2 == '*' || c2 == '/') { //所以和棧頂元素相比 優先順序要小 return '<'; } if (c2 == '(') { return '>'; } if (c2 == ')') { return '<'; } if (c2 == '#') { return '>'; //#是定義為預算結束的標誌符 比所有的操作符優先順序都小 } } if (c == '*' || c == '/') { if (c2 == '+' || c2 == '-') { return '>'; } if (c2 == '*' || c2 == '/') { return '<'; } if (c2 == '(') { return '>'; } if (c2 == ')') { return '<'; } if (c2 == '#') { return '>'; } } if (c == '(') { return '>'; } if (c == ')') { if (c2 != '(') { return '<'; } else { return '='; } } if (c == '#') { if (c2 != '#') { return '<'; } else { return '='; } } return 0; } static int Option(int a, int b, Character c) { switch (c) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; } return 0; } static boolean isOPN(char c) { if (c == '+' || c == '-' || c == '*' || c == '/'||c=='('||c==')'||c=='#') { return false; } else { return true; } } }
輸出結果:
3*(7-2)#
計算結果為:15
難點在於
1.表示式的優先順序區分,要點為更高優先順序的要先計算,比如說3x(1+2),這裡(的優先順序就要比x高,因為要先算括號裡面的,而後面的+的優先順序又要比(高,但是比)小。
2.迴圈的退出條件 直到運算全部結束,即當前棧頂元素和讀入的操作符均為#