若有疑问,请联系simonsliu9@gmail.com,一定尽快回复
求一个可以带括号的小学算术四则运算表达式的值
input
一行,一个四则运算表达式。’*‘表示乘法,’/'表示除法
输入样例1:
3.4
输入样例2:
7+8.3
输入样例3:
3 + 4.5 ∗ ( 7 + 2 ) ∗ ( 3 ) ∗ ( ( 3 + 4 ) ∗ ( 2 + 3.5 ) / ( 4 + 5 ) ) − 34 ∗ ( 7 − ( 2 + 3 ) ) 3+4.5*(7+2)*(3)*((3+4)*(2+3.5)/(4+5))-34*(7-(2+3)) 3+4.5∗(7+2)∗(3)∗((3+4)∗(2+3.5)/(4+5))−34∗(7−(2+3))
output
一行,该表达式的值,保留小数点后面两位
输出样例1:
3.40
输出样例2:
15.30
输出样例3:
454.75
主要实现功能
- 判断左括号
- 判断有括号
- 判断数字,有小数需要判断
- 判断符号,计算
- 不断弹出计算
实现过程
头文件导入
会用到stack来对数字和符号进行存储,也会用到string
#include<iostream>
#include<cstdio>
#include<stack>
#include<cstring>
using namespace std;
定义全局变量
需要的全局变量:
用来存储表达式的字符数组s,保存每一个数字的用作中间变量字符数组temp
符号栈opt,数字栈item
const int maxn = 1000; // 常量
char s[maxn], temp[maxn];
// 一个用于保存表达式,一个用于保存数字从字符数组转化成double变量的中间变量
stack<char> opt;//符号栈
stack<double> item;//数字栈
主要功能函数
- 将字符数组转化成数字
double str2double(char s[])
这个函数一般是将temp中保存的字符数组形式的数字转化成double类型,考虑了小数点
double str2double(char s[]) {
int len = strlen(s);
double sum1 = 0;
double sum2 = 0;
bool flag = false;
for (int i = 0; i < len; i++) {
if (s[i] == '.') {
flag = true;
break;
}
sum1 = sum1 * 10 + s[i] - '0';
}
if (flag) {
for (int i = len - 1; i >= 0; i--) {
if (s[i] == '.') break;
sum2 = (sum2 + s[i] - '0') / 10.0;
}
}
return sum1 + sum2;
}
- 运算符优先级比较函数
int priority(char ch)
int priority(char ch) {
if (ch == '*' || ch == '/') return 2;
if (ch == '+' || ch == '-') return 1;
return 0;
}
- 计算函数
void cal()
void cal() {
double x = item.top();
item.pop();
double y = item.top();
item.pop();
switch (opt.top()) {
case '+': y += x; break;
case '-': y -= x; break;
case '*': y *= x; break;
case '/': y /= x; break;
}
item.push(y);
opt.pop();
}
- 主函数
int main() {
scanf("%s", s); // 输入字符串
int len = strlen(s); // 字符串长度
int cnt = 0; // 中间变量temp的游标
int i = 0; // 对字符串进行遍历的右边
bool flag = false; // 对开头字符是负号的处理flag
// 如果开头是负号,则flag=true,然后表达式遍历游标i+1
if (s[i] == '-') flag = true, i = 1;
// 开始遍历表达式
while (i < len) {
// 如果为左括号,则进栈,游标后移
if (s[i] == '(') opt.push(s[i]),i++;
// 如果为右括号,则计算括号中的值
else if (s[i] == ')') {
while (opt.top() != '(') cal();
opt.pop();
i++;
}
// 如果为数字或者小数点
else if (s[i] <= '9' && s[i] >= '0' || s[i] == '.') {
// 不断的循环,把一个数存入中间变量temp中,然后temp的游标后移,i也后移
while (s[i] <= '9' && s[i] >= '0' || s[i] == '.') temp[cnt++] = s[i++];
// 给中间变量的末尾加一个‘0’,意思表示结尾,便于str2double中计算temp的长度
temp[cnt] = 0;
// 将temp转化为对应的浮点数,然后存入数字栈item中,考虑是否为负数
if (flag) item.push(-str2double(temp)), flag = false;
else item.push(str2double(temp));
// 然后temp的游标归零,便于下一次存储数字
cnt = 0;
}
// 如果为计算符号
else {
// 符号栈opt不为空,同时游标指向的符号的优先级小于栈顶符号优先级,则进行计算
while (!opt.empty() && priority(s[i]) < priority(opt.top())) cal();
// 把当前符号压栈,因为当前符号比栈顶符号优先级大,所以不能拿栈顶符号进行计算
opt.push(s[i]);
i++;
}
}
// 这种情况,是里面的优先级计算顺序已经调整好,直接进行计算
while (!opt.empty()) cal();
printf("%.2lf\n", item.top());
return 0;
}
完整代码
#include<iostream>
#include<cstdio>
#include<stack>
#include<cstring>
using namespace std;
const int maxn = 1000;
char s[maxn], temp[maxn];
stack<char> opt;//符号栈
stack<double> item;//数字栈
double str2double(char s[]) {
int len = strlen(s);
double sum1 = 0;
double sum2 = 0;
bool flag = false;
for (int i = 0; i < len; i++) {
if (s[i] == '.') {
flag = true;
break;
}
sum1 = sum1 * 10 + s[i] - '0';
}
if (flag) {
for (int i = len - 1; i >= 0; i--) {
if (s[i] == '.') break;
sum2 = (sum2 + s[i] - '0') / 10.0;
}
}
return sum1 + sum2;
}
int priority(char ch) {
if (ch == '*' || ch == '/') return 2;
if (ch == '+' || ch == '-') return 1;
return 0;
}
void cal() {
double x = item.top(); item.pop();
double y = item.top(); item.pop();
switch (opt.top()) {
case '+': y += x; break;
case '-': y -= x; break;
case '*': y *= x; break;
case '/': y /= x; break;
}
item.push(y);
opt.pop();
}
int main() {
scanf("%s", s); // 输入字符串
int len = strlen(s); // 字符串长度
int cnt = 0; // 中间变量temp的游标
int i = 0; // 对字符串进行遍历的右边
bool flag = false; // 对开头字符是负号的处理flag
// 如果开头是负号,则flag=true,然后表达式遍历游标i+1
if (s[i] == '-') flag = true, i = 1;
// 开始遍历表达式
while (i < len) {
// 如果为左括号,则进栈,游标后移
if (s[i] == '(') opt.push(s[i]),i++;
// 如果为右括号,则计算括号中的值
else if (s[i] == ')') {
while (opt.top() != '(') cal();
opt.pop();
i++;
}
// 如果为数字或者小数点
else if (s[i] <= '9' && s[i] >= '0' || s[i] == '.') {
// 不断的循环,把一个数存入中间变量temp中,然后temp的游标后移,i也后移
while (s[i] <= '9' && s[i] >= '0' || s[i] == '.') temp[cnt++] = s[i++];
// 给中间变量的末尾加一个‘0’,意思表示结尾,便于str2double中计算temp的长度
temp[cnt] = 0;
// 将temp转化为对应的浮点数,然后存入数字栈item中,考虑是否为负数
if (flag) item.push(-str2double(temp)), flag = false;
else item.push(str2double(temp));
// 然后temp的游标归零,便于下一次存储数字
cnt = 0;
}
// 如果为计算符号
else {
// 符号栈opt不为空,同时游标指向的符号的优先级小于栈顶符号优先级,则进行计算
while (!opt.empty() && priority(s[i]) < priority(opt.top())) cal();
// 把当前符号压栈,因为当前符号比栈顶符号优先级大,所以不能拿栈顶符号进行计算
opt.push(s[i]);
i++;
}
}
// 这种情况,是里面的优先级计算顺序已经调整好,直接进行计算
while (!opt.empty()) cal();
printf("%.2lf\n", item.top());
return 0;
}