我們人類習慣於書寫“中綴式”,如 3 + 5 * 2
,其值爲13
。 (p.s. 爲什麼人類習慣中綴式呢?是因爲中綴式比後綴式好用麼?)
而計算機更加習慣“後綴式”(也叫“逆波蘭式”,Reverse Polish Notation)。上述中綴式對應的後綴式是: 3 5 2 * +
現在,請對輸入的後綴式進行求值。
輸入格式:
在一行中輸入一個後綴式,運算數
和運算符
之間用空格分隔,運算數長度不超過6
位,運算符僅有+ - * /
四種。
輸出格式:
在一行中輸出後綴式的值,保留一位小數。
輸入樣例:
3 5.4 2.2 * +
輸出樣例:
14.9
題意:給定字符串,算出其後綴表達式的結果
方法:典型的棧的操作,當讀入數字時,入棧;當讀到運算符時,彈出棧頂的兩個數進行運算,再把結果加入棧中(用STL的string和stack很容易實現)
注意點分析:
- 判斷負數和小數
- 當做減法和除法運算時,第二個彈出的數纔是被減數或被除數
- 由題意知,除數不會是0,因爲會運算錯誤,題目沒有讓給出錯誤提示
AC代碼如下:
#include<bits/stdc++.h>
using namespace std;
stack<double>num; //聲明一個棧,儲存操作數
double cal(double x1, double x2, char c){ //給定兩個數(x1先彈出)和操作符,得到計算結果
if (c == '+') return x1 + x2;
if (c == '-') return x2 - x1; //注意是x2 - x1和 x2 / x1
if (c == '*') return x1 * x2;
if (c == '/') return x2 / x1;
}
double change(string s) { //把字符串轉成相應的數值
double ans = 0, sign = 1; //sign爲符號,初始爲1
if (s[0] == '-') { //先判斷負數
sign = -1; //標記符號爲負
s.erase(s.begin()); //把首位的負號抹去
}
int cnt = 0, flag = 0; //cnt是小數位的位數(即最後小數點要往左移多少位),flag表示是否發現了小數點,二者初始都是0
for (int i = 0; s[i]; i++) { //遍歷字符串
char c = s[i];
if (c != '.') ans = ans * 10 + c - '0'; //如果是數字,則轉換成對應的值(高位乘10加本位)
else flag = 1; //發現了小數點,flag改爲1
if(c != '.') cnt += flag; //小技巧:當發現了小數點之後,cnt每次都要+1,在此之前不變,即加0;而剛好和flag同步了,則可以直接加flag;這裏的判斷是因爲,剛發現小數點時,cnt不加
}
if(cnt) ans /= pow(10, cnt); //小數點移位操作,即除以10^cnt
return sign * ans; //最後連帶符號返回字符串對應的數值
}
int main() {
string s;
double ans;
getline(cin, s); //對於中間有空格的字符串,要用getline
for (int i = 0; s[i];) { //遍歷字符串
string temp = "";
while (s[i] != ' ' && s[i]) //得到每兩個空格之間的部分
temp += s[i++]; //string類可以把字符直接加到末尾
if (s[i] == ' ') //跳過空格
i++;
if (temp == "+" || temp == "-" || temp == "*" || temp == "/") { //如果是操作符
double x1 = num.top(); //彈出兩個數
num.pop();
double x2 = num.top();
num.pop();
ans = cal(x1, x2, temp[0]); //進行運算
num.push(ans); //再把結果壓入棧中
}
else //是操作數,就把string轉換成double,併入棧
num.push(change(temp));
}
printf("%.1f\n", ans); //輸出最終結果
return 0;
}
//常看我的博客都知道,我的博客講解就像金針菇那麼細,註釋都很詳細的。大神勿噴!
//先看後贊是好習慣哦~