1. 程式人生 > >用逆波蘭表示式實現表示式計算

用逆波蘭表示式實現表示式計算

表示式求值計算,如計算1+((2+3)*4)-5的值。

我的思路是先把表示式轉換為逆波蘭表示式,因為逆波蘭表示式更加符合計算機的處理邏輯,把表示式轉換為逆波蘭表示式的演算法如下:

  1. 初始化兩個棧:運算子棧s2和儲存中間結果的棧s1;
  2. 從左至右掃描中綴表示式;
  3. 遇到運算元時,將其壓s1;
  4. 遇到運算子時,比較其與s2棧頂運算子的優先順序:
    1. 如果s2為空,或棧頂運算子為左括號“(”,則直接將此運算子入棧;
    2. 否則,若優先順序比棧頂運算子的高,也將運算子壓入s2(注意轉換為字首表示式時是優先順序較高或相同,而這裡則不包括相同的情況);
    3. 否則,將s2棧頂的運算子彈出並壓入到s2中,再次轉到(4-1)與s2中新的棧頂運算子相比較;
  5. 遇到括號時:
    1. 如果是左括號“(”,則直接壓入s2;
    2. 如果是右括號“)”,則依次彈出s2棧頂的運算子,並壓入s1,直到遇到左括號為止,此時將這一對括號丟棄;
  6. 重複步驟2至5,直到表示式的最右邊;
  7. 將s2中剩餘的運算子依次彈出並壓入s1

 

字尾表示式求值的演算法如下:

   首先定義一個棧:S3,在該棧中存放最終表示式的值。從左到右遍歷S1,然後按照如下規則操作S3:

(1)如果遇到的是數字,將數字壓入S3中;

(2)如果遇到單目運算子(運算物件只有一個的運算子,如:或(|)、與(&)等),取S3棧頂一個元素進行單目運算,將結果再次壓入S3中;

(3)如果遇到雙目運算子(運算物件有兩個的運算子,如:加(+)、賦值(=)等),取S3棧頂兩個元素(先出棧的在左,後出棧的在右)進行 雙目運算,將結果再次壓入S3中;

按照上面3條規則遍歷完S1,那麼最後S3中的值就是逆波蘭表示式的值了。

  下面是我用java的程式碼實現

  

package com.sun.calculation;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;

/***
 * 中綴表示式計算例如1+((2+3)*4)-5
 * 實現思路就是先把中綴表示式轉換為逆波蘭表示式
 * 然後再對逆波蘭表示式表示式進行計算
 * @author swh
 *
 */
public class ExpressionComputation {

	/***
	 * 先把中綴表示式轉換為字尾表示式
	 * 再對字尾表示式進行計算
	 * @param expression 中綴表示式
	 * @return
	 */
	public static int computation(String expression) {
		
		return getRpnValue(getRpn(expression));
	}

	/***
	 * 中綴表示式轉換為字尾表示式
	 * @param expression
	 * @return
	 */
	private static Queue<Object> getRpn(String expression) {
		Queue<Object> valueQueue = new LinkedList<>();
		Stack<String> optStack = new Stack<>();
		String munStr = ""; 
	    for(int i=0;i<expression.length();i++) {
	    	char ch = expression.charAt(i);
	    	String str = String.valueOf(ch);
	    	if(ch>='0'&&ch<='9') {
	    		munStr +=str;
	    	}else {
	    		if(!munStr.equals("")) {
	    			valueQueue.add(Integer.valueOf(munStr));
	    			munStr="";
	    		}
	    		if (ch=='(') {
	    			optStack.push(str);
	    		}else if (ch==')')  {
	    			  while (optStack.size()!=0&&!optStack.peek().equals("(")) {
	    				  valueQueue.add(optStack.pop());
	                  }
	    			  optStack.pop();
	    		}else {
	    			 while (optStack.size() != 0&&getOptionLevel(optStack.peek())>=getOptionLevel(str)) {
	    				 valueQueue.add(optStack.pop());
	                  }
	    			 optStack.push(str);
	    		}
	    	}
	    }
	    valueQueue.add(Integer.valueOf(munStr));
	    while (optStack.size()!=0) {
			 valueQueue.add(optStack.pop());
         }
	    return valueQueue;
	}
	
	/***
	 * 對字尾表示式進行計算
	 * @param valueQueue
	 * @return
	 */
	public static int getRpnValue(Queue<Object> valueQueue) {
		Stack<Integer> numStack = new Stack<>();
		while(!valueQueue.isEmpty()) {
			if(valueQueue.peek() instanceof Integer) {
				numStack.push((Integer)valueQueue.poll());
			}else {
				String operation = (String)valueQueue.poll();
				numStack.push(getOptionValue(operation, numStack.pop(), numStack.pop()));
			}
		}
		return numStack.pop();
	}
	/***
	 * 得到運算子的優先順序
	 * @param opt
	 */
	public static int getOptionLevel(String operation) {
		 int result = 0;
	        switch (operation){
	            case "+":
	                result=1;
	                break;
	            case "-":
	                result=1;
	                break;
	            case "*":
	                result=2;
	                break;
	            case "/":
	                result=2;
	                break;
	        }
	        return result;
	}
	
	/***
	 * 得到二元運算的值
	 * @param operation
	 * @param b
	 * @param a
	 * @return
	 */
	public static int getOptionValue(String operation,int b,int a) {
		 int result = 0;
	        switch (operation){
	            case "+":
	                result=a+b;
	                break;
	            case "-":
	                result=a-b;
	                break;
	            case "*":
	                result=a*b;
	                break;
	            case "/":
	                result=a/b;
	                break;
	        }
	        return result;
	}
	public static void main(String args[]) {
		computation("1+((2+3)*4)-5");
	}
}

  參考了部落格:

   字首、中綴、字尾表示式(逆波蘭表示式

  逆波蘭表示式演算法