1. 程式人生 > >hdoj 1237 簡單計算器(計算器應用)

hdoj 1237 簡單計算器(計算器應用)

轉自 Bupt Acmer

任意表達式(expression)都是由運算元(operand)操作符(operator)和界限符(delimiter)組成。我們通常習慣使用中綴表示式(infix expression),但中綴表示式離不開括號(bracket)。若使用字首表示式(prefixexpression)或字尾表示式(postfix expression)則不需要括號。利用棧,可以將中綴表示式變為字首表示式或字尾表示式,再用棧進行運算即可得到表示式的值(value)。為了討論的方便,在不影響問題實質的情況下,我們對錶達式做如下簡化:

(1) 假定所有運算分量都是整數;
(2) 所有運算子都是整數的二元操作,且都用一個字元表示。

中綴表示式:表示式中所有運算子都出現在它的兩個運算分量之間。例如:31 * (5 - 22) + 70

字尾表示式:這種表示式裡不再需要有括號,每個運算子都出現在它的兩個運算分量後面。例如:31 5 22 - * 70 +

 5 * (27 + 3 * 7) + 22 轉化為字尾表示式為:5 27 3 7 * + * 22 +

	舉例:31*(5-22)+70 轉換為:31 5 22 - * 70 + 
	31*(5-22)+70          
          *(5-22)+70                           31
	   (5-22)+70               *           31
	    5-22)+70              (*           31
	     -22)+70              (*           31 5
	      22)+70             -(*           31 5
	        )+70             -(*           31 5 22
	         +70               *           31 5 22 -
	          70               +           31 5 22 - *
	                           +           31 5 22 - * 70
	                                       31 5 22 - * 70 + 

 字尾表示式的主要優點是可以寫出非常簡單的求值過程。使用一個存放運算分量(數)的棧,求值過程順序掃描字尾表示式,每次遇到運算分量(數)便將它推入棧中;遇到運算子時,就從棧中彈出兩個整數(運算分量)進行計算,而後再把結果推入棧中。這樣,到掃描結束時,留在棧頂的整數就是所求表示式的值。

        31 5 22 - * 70 +          
           5 22 - * 70 +                        31
	     22 - * 70 +                     5  31
	        - * 70 +                 22  5  31
	          * 70 +                    17  31
	            70 +                       527
		       +                   70  527
	                                       457
	                                       457      計算結束 


 以上例子大概可以看到表示式求值的具體過程和演算法,總結一下:

 有兩種方式,先將中綴表示式轉換成字尾表示式再用字尾表示式求值,或者直接在轉換的過程中求值。


一、 將中綴表示式變為字尾表示式

1.設定一個操作符棧,將“=”壓入堆疊;
2.逐個字元掃描中綴表示式:
3.若當前字元為運算元,直接輸出;
4.若當前字元為“=”,則將堆疊元素全部退棧並輸出,演算法結束;
5.若當前字元為“)”,則堆疊元素開始退棧並輸出,直至遇到“(”,退棧;
6.若當前字元為操作符,則將其與棧頂元素比較優先級別:
7.若當前操作符的優先級別高於棧頂元素,則將當前操作符壓入堆疊;
8.否則,就將棧頂元素退棧並輸出,轉到步驟3繼續比較。

二、 字尾表示式求值

1.設定一個運算元棧;
2.逐個字元掃描字尾表示式:
3.若當前字元為“=”,將結果退棧輸出,演算法結束;
4.若當前字元為運算元,則將該運算元壓入堆疊;
5.否則,當前字元就為操作符,棧頂元素和次棧頂元素退棧,用次棧頂元素“操作”棧頂元素,將運算結果壓入堆疊。、

三、 中綴表示式求值

1.設定兩個堆疊:操作符棧和運算元棧,向操作符棧中壓入“=”;
2.逐個字元掃描中綴表示式:
3.若當前字元為運算元,直接壓入運算元棧;
4.若當前字元為“=”,則將操作符棧元素全部退棧並執行運算操作,最後將運算元棧元素退棧並輸出,演算法結束;
5.若當前字元為“)”,則操作符棧元素退棧並執行運算操作,直至遇到“(”,退棧;
6.若當前字元為操作符,則將其與棧頂元素比較優先級別:
7.若當前操作符的優先級別高於棧頂元素,則將當前操作符壓入堆疊;
8.否則,就將棧頂元素退棧並執行運算操作,轉到步驟3繼續比較;
9.執行元算操作:將運算元棧頂元素和次棧頂元素退棧,用次棧頂元素“操作”棧頂元素,將運算結果壓入運算元棧。

優先級別:

3---“(”;
2---“*”、“/”;
1---“+”、“-”; 
0---“=”、棧中的“(”。

例題分析

hdoj 1237 簡單計算器

 題目大意

 編寫一個只有四則運算的計算器

 題目分析

 沒有括號,只有兩個優先順序的計算器,原始碼採用了直接從中綴表示式到結果的演算法。

 題目原始碼

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<stack>
using namespace std;
stack <double> N; //運算元棧 
stack <char> O;//操作符棧 
double calcul(char oper)//雙目運算子 
{
	double a = N.top(), b;
	N.pop();
	b = N.top();
	N.pop();
	switch(oper){
		case '+':
			return b + a;//加法 
		case '-':
			return b - a;//減法 
		case '*':
			return b * a;//乘法 
		case '/':
			return b / a;//除法 
	}
}
int main()
{
	int len, i; //表示式長度,計數器,數字轉換時記錄小數位 
	double num, a, b;  
	char s[210], oper; //表示式,操作符
	while (gets(s)){ //讀入一行表示式 
		len = strlen(s); //計算出表示式的長度
		if (len == 1 && s[0] == '0')
			break; 
		i = 0;
		while (i < len){ //邊讀入邊計算 
			num = 0;
			while (s[i] == ' ')
				i++; 
			while (((s[i] >= '0' && s[i] <= '9') || s[i] == '.')&& i < len){//將數字由字元型轉換為整型 
				num = num * 10 + s[i] - '0';
				i++;
			}
 			N.push(num);//將轉換後的數字壓入運算元棧 
			while (s[i] == ' ')
				i++;
			switch (s[i]){//處理操作符 
				case '+': case '-'://如果操作符為優先順序最低的加減 
					while (!O.empty()){//比此操作符優先順序高或者相等,此題中所有操作符都符合此條件,略去 
						oper = O.top();//彈出棧頂操作符 
						O.pop();
						N.push(calcul(oper));//將結果壓入堆疊 
					}
				    O.push(s[i]);
					break;
				case '*' : case '/'://如果操作符為優先順序第一的乘除 
				    while (!O.empty() && (O.top() == '*' || O.top() == '/')){//比此操作符優先順序高或者相等 
						oper = O.top();//彈出棧頂操作符 
						O.pop();
						N.push(calcul(oper));//將結果壓入堆疊
				    }
					O.push(s[i]);
					break;
				default :
					break;
			}
			i++; 
		}
		while (!O.empty()){//比將所有的操作符退棧運算 
			oper = O.top();
			O.pop();
			N.push(calcul(oper));
		}
		printf("%.2lf\n", N.top());//列印最終結果 
		N.pop();
	}
	return 0;
}


題目推薦

同學們可自行擴充套件,帶括號的,乘方運算,對數,取模,三角函式,處理異常錯誤,浮點計算器等等。

boj 1441尋求幫助[1]
poj 1686 Lazy Math Instructor[2]