有數字(0~9構成的正整數)、三種操作運算符(加法+、乘法*、自增^)、分隔符一個空格、左右括號
表達式形式是“(運算符 參數)”形式
比如(+ 3 4),求值結果7;(+ (* 2 3)(^4))求值結果11
語法樹結束後,後面加任何字符都是合法的,比如(+ (* 2 3)(^4)))))))#$是合法的
匆匆忙忙地寫了一個,感覺太長了。。。應該有很大的優化空間。
主要思路:用一個var類保存操作數,包括操作符和數字(存在聯合體中,用一個枚舉變量表示類型),然後遍歷輸入的字符串,將左括號、數字、操作符壓入計算棧,當遇到右括號時,彈出數字和操作符進行計算,並彈出左括號,將結果壓入。如果壓入結果之後,計算棧大小爲1,說明語法樹結束啦,直接跳出。中間任何操作失敗,都跳出輸出-1,主要是這個的判斷佔了很大篇幅,得想辦法優化。
#include <iostream>
#include <string>
#include <stack>
#include <unordered_set>
using namespace std;
struct var {
union {
int num;
char op;
};
enum class type {ch,number} ty;
var(int n, type t=type::number) :num(n), ty(t) {}
var(char c, type t= type::ch) :op(c), ty(t) {}
};
using vtype = var::type;
unordered_set<char> ops = { '+','*','^' };
int main() {
string exp;
while (getline(cin,exp)) {
stack<var> cal;
bool valid =true;
for (auto i = exp.cbegin(); i != exp.cend() && valid;++i) {
if (*i >= '0' && *i <= '9') {//數字
int num = *i++ - '0';
while (i!=exp.cend() &&*i >= '0' && *i <= '9') {
num = num * 10 + *i++ - '0';
}
if (i == exp.cend()) {
valid = false;
break;
}
else
cal.emplace(num);
}
if (*i == '(' || ops.find(*i) != ops.end())//左括號或者操作符
cal.emplace(*i);
else if (*i == ')') {//有右括號就彈出東西來計算,如果不對就是不合法的
bool dual;
if (cal.empty() || cal.top().ty != vtype::number) {
valid = false;
break;
}
int rhs = cal.top().num;
int lhs;
int res;
cal.pop();
if (cal.empty()) {
valid = false;
break;
}
if (cal.top().ty == vtype::number) {
dual = true;
lhs = cal.top().num;
cal.pop();
} else if (cal.top().op == '^') {
cal.pop();
res = ++rhs;
dual = false;
} else {
valid = false;
}
if (dual) {
if (!cal.empty() && cal.top().ty == vtype::ch) {
char op = cal.top().op;
cal.pop();
if (op == '+')res = lhs + rhs;
else res = lhs * rhs;
} else {
valid = false;
}
}
if (!cal.empty() && cal.top().ty == vtype::ch && cal.top().op == '(') {
cal.pop();
cal.emplace(res);
} else {
valid = false;
}
if (cal.size() == 1 && cal.top().ty == vtype::number)break;//語法樹結束
} else if (*i == ' ')continue;
else {
if (cal.size() == 1 && cal.top().ty == vtype::number)//非法字符,但是語法樹已結束
break;
else valid = false;
}
}
if (valid && cal.size() == 1 && cal.top().ty == vtype::number) {
cout << cal.top().num << endl;
}
else cout << -1<<endl;
}
return 0;
}