1. 程式人生 > >Java實現表示式計算 藍橋杯

Java實現表示式計算 藍橋杯

題目在這裡http://lx.lanqiao.cn/problem.page?gpid=T419

輸入一個只包含加減乖除和括號的合法表示式,求表示式的值。

表示式計算雖然看起來挺簡單的,但是編碼起來也不是想象中的那麼容易。雖說上課的時候,有講過逆波蘭表示式,但是還沒動手實現過,剛好在藍橋上看到,就動手用Java實踐了一下,c++也類似。

演算法主要是由兩部分組成,一個是將輸入的我們日常使用的中綴表示式轉化為字尾的逆波蘭表示式,這裡可以用排程場演算法實現。轉換成逆波蘭表示式的最主要好處是去掉了括號,同時,使得計算表示式的結果可以只遍歷一次逆波蘭表示式,方便計算。排程場演算法類似於火車排程,從頭到尾遍歷表示式,出現運算元時,直接輸出到結果佇列,出現操作符時,彈出棧中元素直至棧頂操作符優先順序大於當前操作符或者棧為空,再將當前操作符壓入堆疊,當遍歷完表示式時,將堆疊中的操作符依次彈出壓入結果佇列。如果多了括號,則出現(時,將其壓入堆疊,出現)時,將堆疊中的操作符依次彈出壓入結果佇列,直至出現(,(不放入結果佇列。具體可以 參看

https://zh.wikipedia.org/wiki/%E8%B0%83%E5%BA%A6%E5%9C%BA%E7%AE%97%E6%B3%95

第二部分則根據逆波蘭表示式,直接計算表示式的結果。從頭到尾遍歷逆波蘭表示式,將運算元壓入堆疊,遇到操作符,則從堆疊彈出兩個運算元,計算之,再把結果壓入堆疊。在保證輸入合法的情況下,最後結果中堆疊中只有一個元素,就是答案。具體可以參看 https://zh.wikipedia.org/wiki/%E9%80%86%E6%B3%A2%E5%85%B0%E8%A1%A8%E7%A4%BA%E6%B3%95

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


public class Main {
	
	public static void main(String[] args) {
		Scanner cin = new Scanner(System.in);
		while(cin.hasNext()){
			String s = cin.nextLine();
			
			//將中綴表示式轉化為字尾表示式
			Queue<Object> queue = new LinkedList<Object>();
			Stack<Character> stack = new Stack<Character>();
			int x = 0;
			boolean isInt =false;
			for(int i=0; i<s.length(); i++){
				char ch = s.charAt(i);
				if(ch>='0'&&ch<='9'){
					x = x*10 + ch-'0';
					isInt = true;
				}else{
					if(isInt)
						queue.add((Integer)x);
					x = 0;
					isInt = false;
					if(ch=='('){
						stack.push(ch);
					}else if(ch==')'){
//						System.out.println(stack);
//						System.out.println(queue);
						while(stack.peek()!='('){
//							System.out.println(stack.peek());
							queue.add(stack.pop());
						}
						stack.pop();
					}else{
						while(!stack.empty() && rank(stack.peek())>=rank(ch)){
							queue.add(stack.pop());
						}
						stack.push(ch);
					}
				}
			}
			if(x!=0) queue.add(x);
			while(!stack.empty()) queue.add(stack.pop());
			
//			計算逆波蘭表示式
			Stack<Integer> integers = new Stack<Integer>();
			for(Object object : queue){
				if(object instanceof Integer){
					integers.push((Integer)object);
				}else{
					int b = integers.pop();
					int a = integers.pop();
					char op = (Character)object;
					if(op=='+') integers.push(a+b);
					else if(op=='-') integers.push(a-b);
					else if(op=='*') integers.push(a*b);
					else integers.push(a/b);
				}
			}
			System.out.println(integers.peek());
		}
	}
	
	private static int rank(char ch){
		if(ch=='+'||ch=='-'){
			return 1;
		}else if(ch=='*' || ch=='/'){
			return 2;
		}else{	//( ) 
			return 0;	//( ) 的優先順序應該跟高,但這裡為了程式碼的簡潔,將其設為最小
		}
	}
}