问题描述
输入一个只包含加减乖除和括号的合法表达式,求表达式的值。其中除表示整除。
输入格式
输入一行,包含一个表达式。
输出格式
输出这个表达式的值。
样例输入
1-2+3*(4-5)
样例输出
-4
数据规模和约定
表达式长度不超过100,表达式运算合法且运算过程都在int内进行。
这道题很偏向应用,因为这是计算器的常见写法。或者说底层计算器的常见写法.
此代码不止限于计算此题,此代码还可计算小数类型。但负数以及异常处理,暂时还没写
需要用到栈来实现,涉及知识点为后缀表达式(逆波兰表达式)。可以参考这几位大侠的文章《原表达式转换为后缀表达式》
此题的思路可以把数据转为中缀表达式跟后缀表达式。然后进行计算。但是这样有点太过麻烦。
我的思路是:
1.用两个栈,一个存放数据, 一个存放运算符
2.数据的栈,按顺序压入。而运算符的栈是一个单调栈,栈底运算符优先级是最低的, 栈顶优先级最高
3.为保证单调栈的实现,如果栈顶元素优先级高于当前运算符,则先以逆波兰算法计算表达式的值,直到栈顶元素优先级低于当前运算符(注意判断非空)
4. 遇到右括号)时,计算直到左括号我(为止的值。左扩号在压栈时也需要特殊处理)
5.注意处理几个符号连续的问题。(本想在括号里单独处理,结果越写越麻烦, 因为"(+"与“)+”两个很不相同)
/*
作者:贯穿真Sh
时间:2018年7月25日23:15:46
表达式计算:使用逆波兰表达式(这里为方便没有转中缀,后缀表达式)
模拟底层数据的运作方式
输入一个表达式,如1+2*(3-4),输出它的值
思路,使用两个栈
一个数据栈,一个运算符的单调栈
遇到小括号时,计算小括号的再把新数据压栈
只有当前操作符的优先级高于操作符栈栈顶的操作符的优先级,才入栈,否则弹出操作符以及操作数进行计算直至栈顶操作符的优先级低于当前操作符
,然后将当前操作符压栈。当所有的操作符处理完毕(即操作符栈为空时),操作数栈中剩下的唯一一个元素便是最终的表达式的值
暂没解决负数的问题,其中一个思路是把减号全当负号,然后需要时补充加号,变成加某个负数
此程序还没有处理一些异常问题。只写了一半
*/
#include<iostream>
#include<stack>
#include<string>
using namespace std;
stack<double> data;
stack<char> oper;
//处理运算符优先级
int priority(char symbol)
{
switch(symbol)
{
case '+':
case '-':
return 1;
case '*':
case '/':
return 2;
case '(':
return 0;
default:
return -1;
}
}
int calculate()
{
char top = oper.top();
oper.pop();
//如果是'(', 返回0
if(top == '(')
return 0;
double first = data.top();
data.pop();
double second = data.top();
data.pop();
if(top == '+')
data.push(first + second);
else if(top == '-')
//由于倒过来了,second才是表达式中较前的数
data.push(second - first);
else if(top == '*')
data.push(first * second);
else if(top == '/')
{
if(second == 0)
{
cout << "不能除以0" << endl;
return -1;
}
data.push(second / first);
}
else
{
cout << oper.top();
cout << "输入符号有误" << endl;
return -1;
}
return 1;
}
int main()
{
string str;
cin >> str;
int len = str.length();
double sum = 0;
double carry = 10;//进位,可以用来控制小数以及整数
bool open = true; //用于控制data的push开关。防止两个符号连续时push 0的问题
for(int i = 0; i < len; i++)
{
//处理数字
if(str[i] <= '9' && str[i] >= '0')
{
sum = str[i] - '0' + sum * carry;
//最后一个是数字的话要特殊处理
if(i == len - 1)
{
data.push(sum);
}
open = true;
}
//处理小数问题:遇到小数点后面每个位除以10
else if(str[i] == '.')
{
carry = 0.1;
}
else
{
//处理两个符号连续的问题
if(open)
{
data.push(sum);
}
open = false;
sum = 0;
//遇到)时,先处理小括号内的值
if(str[i] == ')')
{
//计算括号里的数据,:直到遇到左括号结束循环
while(calculate() != 0)
{
}
}
else
{
//当前运算符优先级比栈顶元素值大时,入栈, 否则先将前面的表达式计算结果后在加入栈 , 直到操作符优先级比栈顶大, '('括号优先级设为最低是因为方便计算
while(str[i] != '(' && !oper.empty() && (priority(oper.top()) > priority(str[i])))
{
calculate();
}
oper.push(str[i]);
}
}
}
while(!oper.empty())
calculate();
cout << data.top() << endl;
return 0;
}