概述
题目链接:2017 计蒜之道 初赛 第二场——百度的科学计算器(简单)
给定一个合法的字符串(可以含有整数、小数、加号、减号、括号)的字符串,计算其值
// 将s分隔成多个整体(整数、小数、运算符、括号中的部分均算作一个整体)
std::vector<std::string> split(const std::string& s) {
std::vector<std::string> ret;
if (s.length() == 0) return ret;
// bracket
if (s.at(0) == '(') {
int cnt = 0;
for (int i = 0; i < s.length(); i++) {
if (s.at(i) == '(') cnt++;
else if (s.at(i) == ')') cnt--;
if (cnt == 0) {
ret.push_back(s.substr(0, i + 1));
auto r = split(s.substr(i + 1));
std::copy(r.begin(), r.end(), std::back_inserter(ret));
break;
}
}
}
// number
else if (('0' <= s.at(0) && s.at(0) <= '9') || s.at(0) == '.') {
ret.push_back("");
for (int i = 0; i < s.length(); i++) {
if (('0' <= s.at(i) && s.at(i) <= '9') || s.at(i) == '.')
ret.back() += s.at(i);
else {
auto r = split(s.substr(i));
std::copy(r.begin(), r.end(), std::back_inserter(ret));
break;
}
}
}
// operator
else {
ret.push_back(s.substr(0, 1));
auto r = split(s.substr(1));
std::copy(r.begin(), r.end(), std::back_inserter(ret));
}
return ret;
}
// 支持s中含有括号、小数、整数、加号、减号
double calc(std::string s) {
auto parts = split(s);
if (parts.size() == 0)
return 0;
if (parts.size() == 1) {
// 如果给定字符串是括号括起来的表达式
if (s.at(0) == '(')
return calc(s.substr(1, s.length() - 2));
else {
assert(('0' <= s.at(0) && s.at(0) <= '9') || s.at(0) == '.');
// stod函数是c++11标准支持的,需要编译器不能太老
return std::stod(s);
}
}
double ret = calc(parts.at(0));
for (int i = 1; i < parts.size(); i += 2) {
assert(i + 1 < parts.size());
if (parts.at(i) == "+")
ret += calc(parts.at(i + 1));
else if (parts.at(i) == "-")
ret -= calc(parts.at(i + 1));
else
assert(false);
}
return ret;
}
int main(int argc, char *argv[]) {
int n; std::cin >> n;
std::string s;
std::cin >> s;
double ans = calc(s);
if (s.find(".") == std::string::npos)
std::cout << (long long)ans << std::endl;
else
printf("%.6fn", ans);
return 0;
}
另一种比较好的写法,修改自这个blog
这段代码主要思路是:建立表达式树
template<class T>
class Calc {
static const int MX = 100000;
char op[MX];
int lch[MX], rch[MX], r = 0;
T s[MX];
bool DIV_ZERO;
int _build(const std::string& S, int L, int R) {
int u;
int t = L;
while (t <= R && (isdigit(S.at(t)) || S.at(t) == '.')) t++;
if (t == R + 1) {
u = r++;
op[u] = '.';
lch[u] = rch[u] = -1;
s[u] = std::stod(S.substr(L, t - L));
return u;
}
std::vector<int> c = { -1, -1 };
for (int i = L, p = 0; i <= R; i++) {
if (S.at(i) == '(') p++;
else if (S.at(i) == ')') p--;
else if ((S.at(i) == '+' || S.at(i) == '-') && !p) c.at(0) = i;
else if ((S.at(i) == '*' || S.at(i) == '/') && !p) c.at(1) = i;
}
if (c.at(0) < 0)
c.at(0) = c.at(1);
if (c.at(0) < 0)
u = _build(S, L + 1, R - 1);
else {
u = r++;
op[u] = S[c[0]];
lch[u] = _build(S, L, c[0] - 1);
rch[u] = _build(S, c[0] + 1, R);
s[u] = -1;
}
return u;
}
T _calc(int u) {
if (op[u] == '.') return s[u];
T al = _calc(lch[u]), ar = _calc(rch[u]);
switch (op[u]) {
case '+': return al + ar;
case '-': return al - ar;
case '*': return al * ar;
case '/': return (ar == 0 ? DIV_ZERO = 1 : al / ar);
}
assert(false); return al;
}
public:
T solve(const std::string& s) {
r = 0;
DIV_ZERO = false;
int u = _build(s, 0, (int)s.length() - 1);
if (!DIV_ZERO)
return _calc(u);
else
/// 运算过程中发生除0
return INF;
}
};
Calc<long long> int_calc;
Calc<long double> dbl_calc;
int main() {
int n;
while (std::cin >> n) {
std::string expr;
std::cin >> expr;
if (expr.find(".") == std::string::npos) {
long long ans = int_calc.solve(expr);
printf("%lldn", ans);
}
else {
long double ans = dbl_calc.solve(expr);
printf("%.6fn", (double)ans);
}
}
return 0;
}
最后
以上就是过时砖头为你收集整理的c++实现简单eval的全部内容,希望文章能够帮你解决c++实现简单eval所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复