hdoj 1237 簡單計算器(計算器應用)
阿新 • • 發佈:2019-01-27
轉自 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]