Description
二哥想自己做一个计算器,但是他需要一个程序来计算输入表达式的结果。你能帮助他吗?
Input Format
输入仅一行,给出一个算数表达式。表达式中包含:小括号,加减乘除,指数运算符,负号,整数,空格。其中负号的优先级最高(-),其次是指数运算(^),然后是乘除(*/),最后是加减(+-)。
这里规定除法为整除运算,如 5 / 2 = 2, 8 / -3 = -2 等等,与C++中的整除一致。另外注意指数运算为右结合,即 2^3^2 = 2^9 = 512 而非 2^3^2 = 8^2 = 64 。
输入的字符串长度不超过100。
Output Format
如果输入的表达式出现括号不匹配或者除零错误,输出一行“Error”(不含引号),否则输出运算结果。输入保证不包含任何其它类型的错误。
输入的数,输出的答案,以及中间结果均保证是不超过 long long 范围的整数。
Sample Input
5 + (1 + 3) * 6 ^ 1
Sample Output
29
Sample Input
(6 + 2)) * 3
Sample Output
Error
说明
30%的测试数据含有负号;
30%的测试数据含有指数运算。
#include <iostream> #include <memory> #include <stack> #include <fstream> #include <vector> #include <cmath> #include <iomanip> #include <exception> #include <climits> #include <array> #include <cstdint> using namespace std; class Token { public: virtual bool isOperator()=0; virtual ~Token() {} }; class ValueToken : public Token { public: long long value; long long get_value(){ return value;} virtual bool isOperator() { return false; } explicit ValueToken(long long val) : value(val) {} }; class OperatorToken : public Token { public: enum OpType { BGN=0, END, ADD, MNS, NEG, MUL, DIV, POW, LBK, RBK } optr; virtual bool isOperator() { return true; } char get_char(){ switch (optr){ case BGN: return '@'; case END: return '$'; case ADD: return '+'; case MNS: return '-'; case NEG: return '#'; case MUL: return '*'; case DIV: return '/'; case POW: return '^'; case LBK: return '('; case RBK: return ')'; default: return '?'; } } explicit OperatorToken(OperatorToken::OpType op) : optr(op) {} bool is_prior(const OperatorToken& r){ return prior_table[this->optr][r.optr]; } static bool prior_table[10][10]; }; bool OperatorToken::prior_table[10][10]={ //BGN, END, ADD, MNS, NEG, MUL, DIV, POW, LBK, RBK {0,0,0,0,0,0,0,0,0,0},//BGN {1,0,0,0,0,0,0,0,0,0},//END {1,1,0,0,0,0,0,0,1,0},//ADD {1,1,0,0,0,0,0,0,1,0},//MNS {1,1,1,1,0,1,1,1,1,0},//NEG {1,1,1,1,0,0,0,0,1,0},//MUL {1,1,1,1,0,0,0,0,1,0},//DIV {1,1,1,1,0,1,1,1,1,0},//POW {1,1,1,1,1,1,1,1,1,0},//LBK {1,1,0,0,0,0,0,0,1,0},//RBK }; vector<shared_ptr<Token>> pre_process(const string &str) { vector<shared_ptr<Token>> ret; ret.emplace_back(new OperatorToken(OperatorToken::BGN)); long long val = 0; bool f = false, is_neg = true; for (char c:str) { if (c >= '0' && c <= '9') { if (f)val = val * 10 + c - '0'; else val = c - '0'; is_neg= false; f = true; } else { if (f) { ret.emplace_back(new ValueToken(val)); } switch (c) { case '+': ret.emplace_back(new OperatorToken(OperatorToken::ADD)); is_neg=true; break; case '-': ret.emplace_back(new OperatorToken(is_neg?OperatorToken::NEG:OperatorToken::MNS)); is_neg=true; break; case '*': ret.emplace_back(new OperatorToken(OperatorToken::MUL)); is_neg=true; break; case '/': ret.emplace_back(new OperatorToken(OperatorToken::DIV)); is_neg=true; break; case '^': ret.emplace_back(new OperatorToken(OperatorToken::POW)); is_neg=true; break; case '(': ret.emplace_back(new OperatorToken(OperatorToken::LBK)); is_neg=true; break; case ')': ret.emplace_back(new OperatorToken(OperatorToken::RBK)); is_neg= false; break; case ' ': break; default: break; } val = 0; f = false; } } if(f)ret.emplace_back(new ValueToken(val)); ret.emplace_back(new OperatorToken(OperatorToken::END)); return ret; } void print(const vector<shared_ptr<Token>> v){ for(auto p:v){ if(p->isOperator()){ cout<<static_pointer_cast<OperatorToken>(p)->get_char(); } else{ cout<<static_pointer_cast<ValueToken>(p)->get_value(); } } } void compute(stack<shared_ptr<OperatorToken>>& optrs, stack<long long>& vals){ long long l,r,s; auto op=optrs.top()->optr; optrs.pop(); switch (op){ case OperatorToken::ADD: if(vals.size()<2)throw exception(); r=vals.top(); vals.pop(); l=vals.top(); vals.pop(); vals.push(l+r); #ifdef DEBUG cout<<l<<"+"<<r<<"="<<vals.top()<<endl; #endif break; case OperatorToken::MNS: if(vals.size()<2)throw exception(); r=vals.top(); vals.pop(); l=vals.top(); vals.pop(); vals.push(l-r); #ifdef DEBUG cout<<l<<"-"<<r<<"="<<vals.top()<<endl; #endif break; case OperatorToken::NEG: if(vals.size()<1)throw exception(); l=vals.top(); vals.pop(); vals.push(-l); #ifdef DEBUG cout<<" neg "<<l<<"="<<vals.top()<<endl; #endif break; case OperatorToken::MUL: if(vals.size()<2)throw exception(); r=vals.top(); vals.pop(); l=vals.top(); vals.pop(); vals.push(l*r); #ifdef DEBUG cout<<l<<"*"<<r<<"="<<vals.top()<<endl; #endif break; case OperatorToken::DIV: if(vals.size()<2)throw exception(); r=vals.top(); vals.pop(); if(!r)throw exception(); l=vals.top(); vals.pop(); vals.push(l/r); #ifdef DEBUG cout<<l<<"/"<<r<<"="<<vals.top()<<endl; #endif break; case OperatorToken::POW: if(vals.size()<2)throw exception(); r=vals.top(); vals.pop(); l=vals.top(); vals.pop(); s=pow(l,r); vals.push(s); #ifdef DEBUG cout<<l<<"^"<<r<<"="<<vals.top()<<endl; #endif break; case OperatorToken::RBK: if(optrs.top()->optr!=OperatorToken::LBK)throw exception(); optrs.pop(); #ifdef DEBUG cout<<"()"<<endl; #endif break; case OperatorToken::END: optrs.pop(); break; default: throw exception(); break; } } int main() { string string1; getline(cin,string1); auto s = pre_process(string1); stack<shared_ptr<OperatorToken>> optrs; stack<long long> vals; optrs.push(dynamic_pointer_cast<OperatorToken>(s[0])); try{ for(auto& ptoken:s){ if(ptoken==s[0])continue; if(!ptoken->isOperator())vals.push(dynamic_pointer_cast<ValueToken>(ptoken)->value); else{ shared_ptr<OperatorToken> ptr=dynamic_pointer_cast<OperatorToken>(ptoken); while (!ptr->is_prior(*optrs.top())){ compute(optrs,vals); } optrs.push(ptr); } } if(vals.size()!=1||optrs.size()!=2)throw exception(); }catch (exception e){ cout<<"Error"; return 0; } cout<<vals.top(); return 0; }