【问题描述】
设计一个程序,对输入的以#为结束的算术表达式(包括+,-,*,/,(,) ),首先判断表达式是否含有非法字符(即非+,-,*,/, (,) 之外的字符),
如果含有非法字符,则报错误信息;
如果正确,计算并输出这个表示式的值。
本题希望利用算符优先关系,实现对算术四则混合运算表达式的求值。
【输入格式】
以#为结束符的算术表达式。
【输出格式】
对于每组测试数据算术表达式,如果含有非法字符,输出“NO”,否则输出表达式的值,行尾不得有多余的空格。
要求:
使用STL求解表达式的值。
【样例输入】
3+4*(5-3)#
【样例输出】
11
【样例说明】
输入样例是合法的表达式,因此求表达式的值,并输出11。
【样例输入】
3+;4*(5-3)#
【样例输出】
表达式不合法
【样例说明】
输入样例含不合法的字符';',因此输出“NO”。
【特别说明】
建议使用STL
【思路分析】
这种表达式称为中缀表达式,做法有二,1:可以开辟两个栈直接解决,2:先把中缀表达式转化成后缀表达式再进行求解。本题采用的做法为2。
转化成后缀表达式规则:
1.设定运算符栈;
2.从左到右遍历中缀表达式的每个数字和运算符;
3.若当前字符是数字,则直接输出成为后缀表达式的一部分;
4.若当前字符为运算符,则判断其与栈顶运算符的优先级,若优先级大于栈顶运算符,则进栈;若优先级小于等于栈顶运算符,退出栈顶运算符成为后缀表达式的一部分,然后将当前运算符放入栈中;
5.若当前字符为“(”,进栈;
6.若当前字符为“)”,则从栈顶起,依次将栈中运算符出栈成为后缀表达式的一部分,直到碰到“(”。将栈中“(”出栈,不需要成为后缀表达式的一部分,然后继续扫描表达式直到最终输出后缀表达式为止。
注意本题中表达式中的数字并不是一位数,需要用cin读取。转化成后缀表达式时不能用string接收,需要用vector进行隔断。本题做法并不是最佳,仅作参考。
#include<vector>
#include<algorithm>
#include<iostream>
#include <stack>
#include <sstream>
using namespace std;
int calculate(const string &s) {
stringstream ss(s);
stack<char> opers;
stack<int> nums;
int x;
char oper;
vector<string> regex;
for (int i = 0; i < s.size(); i++) {
//由于stringstream一次性输入数字和符号,符号后可能紧跟着'(',需要特判
if (s[i]=='#'){
break;
} else if (s[i] > '0' && s[i] < '9') {
ss >> x >> oper;
regex.push_back(to_string(x));
} else {
ss >> oper;
goto flag;
}
while (x /= 10)i++;
i++;//计数,i为当前字符串下标
flag:
if (opers.empty()) {
opers.push(oper);
} else if (oper == '(') {
opers.push(oper);
} else if (oper == ')') {
while (opers.top() != '(') {
string tmp;
tmp.push_back(opers.top());
regex.push_back(tmp);
opers.pop();
}
opers.pop();
} else if ((oper == '-' || oper == '+') && !opers.empty() && opers.top() != '(') {
while (!opers.empty()) {
string tmp;
tmp.push_back(opers.top());
regex.push_back(tmp);
opers.pop();
}
opers.push(oper);
} else if (!opers.empty() && opers.top() == '(') {
opers.push(oper);
} else if (oper == '*' || oper == '/') {
opers.push(oper);
} else if (oper == '#') {
break;
}
}
while (!opers.empty()) {
string tmp;
tmp.push_back(opers.top());
regex.push_back(tmp);
opers.pop();
}
//此处进行后缀表达式的计算
for (string i: regex) {
if (i[0] > '9' || i[0] < '0') {
int a = nums.top();
nums.pop();
int b = nums.top();
nums.pop();
switch (i[0]) {
case '+':
nums.push(a + b);
break;
case '-':
nums.push(b - a);
break;
case '*':
nums.push(a * b);
break;
case '/':
nums.push(b / a);
break;
}
} else {
ss.str(string());
ss.clear();//清空ss,不需要创建新的stringstream对象
ss << i;
int tmp;
ss >> tmp;
nums.push(tmp);
}
}
return nums.top();
}
int main() {
string s;
cin >> s;
for (int i = 0; i < s.size(); i++) {
if ((s[i] != '+' && s[i] != '-' && s[i] != '(' && s[i] != ')' && s[i] != '/' && s[i] != '*' && s[i] != '#') &&
(s[i] < '0' ||
s[i] > '9')) {
cout << "NO";
return 0;
}
}
cout << calculate(s) << endl;
}