华为笔试,语法树,用单行的类LISP语法字符串表示

有数字(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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值