有数字(0~9构成的正整数)、三种操作运算符(加法+、乘法*、自增^)、分隔符一个空格、左右括号
表达式形式是“(运算符 参数)”形式
比如(+ 3 4),求值结果7;(+ (* 2 3)(^4))求值结果11
语法树结束后,后面加任何字符都是合法的,比如(+ (* 2 3)(^4)))))))#$是合法的
匆匆忙忙地写了一个,感觉太长了。。。应该有很大的优化空间。
主要思路:用一个var类保存操作数,包括操作符和数字(存在联合体中,用一个枚举变量表示类型),然后遍历输入的字符串,将左括号、数字、操作符压入计算栈,当遇到右括号时,弹出数字和操作符进行计算,并弹出左括号,将结果压入。如果压入结果之后,计算栈大小为1,说明语法树结束啦,直接跳出。中间任何操作失败,都跳出输出-1,主要是这个的判断占了很大篇幅,得想办法优化。
#include
#include
#include
#include
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 ops = { '+','*','^' };
int main() {
string exp;
while (getline(cin,exp)) {
stack 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<
}
return 0;
}