题目描述
计算非负整常数四则运算表达式,可用的运算符有:+ - * / ( ) 。
输入格式
一组非负整常数四则运算表达式,每个表达式输入一行,长度不超过1024个字符,每对括号内一定包含数字。
输出格式
每个表达式的计算结果输出一行,错误的表达式输出error。
输入样例
12+5 -4-7 3-*5 ((12-3)/2)+5 3+7/(2-2)
输出样例
17 error error 9 error
数据范围与提示
算法流程:
E1:设立运算符栈和操作数栈;
E2:开始运算符#入栈,向表达式串尾添加结束运算符#;
E3:逐词读入表达式,并处理:
E31:若读入为操作数,则入栈;
E32:若读入为运算符,则与栈顶运算符相比较:
E321:若栈顶运算符优先级高于读入运算符:
弹出栈顶运算符和两个操作数,计算并将结果入栈,执行步骤E32;E322:若栈顶运算符优先级低于读入运算符:
则将读入运算符入栈,执行步骤E3;E323:若栈顶运算符优先级等于读入运算符:
若为#,计算结束,若为括号,则弹出运算符,执行步骤E3。E4:检查栈状态,得到计算结果;
#include<iostream>
#include<string>
#include<stack>
#include<cctype>
using namespace std;
int func(string org)
{
int temp=0;
stack<char> test;
int num[1024]={0};
int index=0;
char op[1024];
stack<int> number;
int flag=0;
for(int i=0;i<org.length();i++)
{
char tp=org[i];
if(isdigit(org[i]))
{
temp*=10;
temp+=org[i]-'0';
flag=1;
}
else
{
if(flag){
num[index]=temp;
op[index]='!';
index++;
flag=0;
temp=0;
}
if(org[i]=='#'){
while(!test.empty())
{
op[index++]=test.top();
test.pop();
}
break;
}
else{
if(test.empty()||org[i]=='(')
{
test.push(org[i]);
}
else if(org[i]==')'){
while(!test.empty()&&test.top()!='(')
{
op[index++]=test.top();
test.pop();
}
if(!test.empty()) test.pop();
else return -1;
}
else if(org[i]=='*'||org[i]=='/'){
while(!test.empty()&&(test.top()=='*'||test.top()=='/'))
{
op[index++]=test.top();
test.pop();
}
test.push(org[i]);
}
else{
while(!test.empty()&&test.top()!='(')
{
op[index++]=test.top();
test.pop();
}
test.push(org[i]);
}
}
}
}
int temp1=0,temp2=0;
for(int i=0;i<index;i++)
{
if(op[i]=='!')
{
number.push(num[i]);
}
else
{
temp1=number.top();
number.pop();
if(number.empty()) return -1;
temp2=number.top();
number.pop();
switch(op[i])
{
case '+':
number.push(temp2+temp1);
break;
case '-':
number.push(temp2-temp1);
break;
case '*':
number.push(temp2*temp1);
break;
case '/':
if(temp1==0) return -1;
number.push(temp2/temp1);
break;
}
}
}
return number.top();
}
int brackets(string org)
{
int mark=0;
for(int i=0;i<org.length();i++)
{
if(org[i]=='(') mark++;
if(org[i]==')') mark--;
}
return mark;
}
int main()
{
string org;
while(cin>>org)
{
if(brackets(org))
{
cout<<"error"<<endl;
}
else
{
org+='#';
int result;
result=func(org);
if(result==-1)
{
cout<<"error"<<endl;
}
else cout<<result<<endl;
}
}
return 0;
}
写了半天,最后借鉴了大佬的代码。
头文件和命名空间:
引入了
<iostream>
,<string>
,<stack>
, 和<cctype>
,用于输入输出、字符串处理、栈操作及字符判断。
func
函数:
负责将输入字符串(表达式)转换为后缀表达式,并计算其值。
使用两个栈:一个字符栈
test
用于存储运算符,另一个整型栈number
用于存储操作数。循环遍历输入字符串,处理数字、运算符和括号:
当遇到数字时,将其拼接成完整的数字。
遇到运算符时,根据优先级进行处理,并将结果存入
op
数组。遇到括号时,按照括号的规则进行入栈和出栈。
brackets
函数:
检查表达式中的括号是否匹配,通过计数左括号和右括号的数量来实现。
main
函数:
循环读取用户输入的表达式,检查括号匹配,若不匹配则输出“error”。
将表达式末尾添加
#
作为结束标志,调用func
计算结果,若结果为-1
,则输出“error”;否则输出计算结果。
对func函数详细分析
temp: 用于临时存储当前读取的数字。
test: 一个字符栈,用于存储操作符。
num: 存储读取到的数字。
index: 数组 num 和 op 的索引,用于记录操作数和操作符的数量。
op: 存储操作符(如 +、-、*、/)。
number: 一个整数栈,用于存储操作数。
flag: 标记当前是否正在读取一个数字。负责将输入字符串(表达式)转换为后缀表达式,并计算其值。
1. 操作符的处理
操作符的处理分为两部分:处理栈的逻辑和操作符的优先级。
2. 处理括号的逻辑
左括号
(
:
如果栈为空或当前字符是
(
,则直接将其推入栈中。这表明我们遇到了一个新的子表达式。
右括号
)
:
当遇到右括号
)
时,程序需要将栈中操作符弹出直到遇到左括号(
。弹出过程中,将操作符存入
op
数组。如果没有找到对应的左括号,返回错误 -1。
处理乘法和除法操作符
对于乘法
*
和除法/
,由于它们的优先级较高,程序需要在推入当前操作符之前,检查栈中是否已经有相同或更高优先级的操作符。如果有,则将它们弹出并存入
op
数组。处理加法和减法操作符
对于加法
+
和减法-
,处理逻辑类似于乘法和除法,但需要注意的是,加法和减法的优先级较低。只要遇到操作符,就弹出所有在栈中的操作符,直到遇到左括号为止。