NC50999 表达式计算4
链接:https://ac.nowcoder.com/acm/problem/50999
来源:牛客网
题目描述
给出一个表达式,其中运算符仅包含+,-,*,/,^(加 减 乘 整除 乘方)要求求出表达式的最终值
数据可能会出现括号情况,还有可能出现多余括号情况
数据保证不会出现 ≥ 2 31 \geq 2^{31} ≥231 的答案
数据可能会出现负数情况
输入描述:
仅一行,即为表达式
输出描述:
仅一行,既为表达式算出的结果
示例1
输入
(2+2)^(1+1)
输出
16
备注:
表达式总长度≤30
代码
#include <bits/stdc++.h>
using namespace std;
/*
虽然通过了示例(有瑕疵,有的错误没覆盖到),但是可能还有bug
目前额外添加了网上其他同学的测试样例,都通过了:
(-5)^2))))+2=27
2+2^4/8-6=-2
3+(2*5+7^2)-6*(3+2)=32
123+444*2^2/111-24=115
100-5*5^(1+2)/5+25=0
()0+2=2
(()-2=-2
)(0+2=2
-2^(-2)-2=-1.75
*/
stack<char> operation;
stack<double> number;
char table[7][7] = {
//+ - * / ( ) ^
{'>','>','<','<','<','>','<'},//+
{'>','>','<','<','<','>','<'},//-
{'>','>','>','>','<','>','<'},//*
{'>','>','>','>','<','>','<'},// /
{'<','<','<','<','<','=','<'},//(
{'>','>','>','>','<','>','>'},//)
{'>','>','>','>','<','>','>'} //^
};
int get_index(char op) {
switch (op)
{
case'+':return 0;
case'-':return 1;
case'*':return 2;
case'/':return 3;
case'(':return 4;
case')':return 5;
case '^':
return 6;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return -2;
default:
return -1;
}
}
char priority(char op1, char op2) {
return table[get_index(op1)][get_index(op2)];
}
//去除多余括号
void delete_redundant_brackets(string& s) {
struct node
{
int index;
char bracket;
};
int last_left = -1;
//括号匹配,找出多余的括号
stack<node> brackets;
for (int i = 0; i < s.size(); i++) {
node t;
t.bracket = s[i];
t.index = i;
if (s[i] == ')')
{
if (last_left!=-1&& last_left+1==i)//避免()连在一起的情况
{
brackets.push(t);
t.bracket='(';
t.index = last_left;
brackets.push(t);
}else if (!brackets.empty()&& brackets.top().bracket=='(')//括号匹配了
{
brackets.pop();
}
else
{
//也是多余的,要去除
brackets.push(t);
}
}
else if (s[i] == '(') {
brackets.push(t);
last_left = i;
}
}
//删除多余括号
while (!brackets.empty())
{
int i = brackets.top().index;
s=s.erase(i,1);
brackets.pop();
}
}
// 循环版 快速幂
double fast_power(int base, int power) {
double result = 1;
if (power<0)//解决负指数的情况
{
power = -power;
result = 1.0 / fast_power(base, power);
}
else
{
while (power > 0) {
if (power & 1) {
result = result * base;
}
power >>= 1;
base = base * base;
}
}
return result;
}
double cal(double num1, char opt, double num2) {
switch (opt)
{
case'+':return num1+num2;
case'-':return num1 - num2;
case'*':return num1 * num2;
case'/':return num1 / num2;
case '^':
return fast_power(num1,num2);
default:
return -10000;
}
}
int main()
{
string s,t="(";
cin >> s;
if (!s.size())
{
return 0;
}
//先删除多余括号,不能放在添加括号之后,否则会导致运算中途停止,例如此示例(这个错误oj没有检测出来):1+((-2)*2+3=0;(1+((-2)*2+3)->1+((-2)*2+3)=1 此处的1是((-2)*2+3)运算的结果
delete_redundant_brackets(s);
//给表达式加上括号,避免操作符栈为空,运算中途停止
t += s;
t += ")";
s = t;
int index = 0,sign = 1;
double ans = 0;
do {
int num = 0;
int t= get_index(s[index]);
//操作符
if (t != -2&& t != -1) {
//判断是否是负号,前面的字符是没有或者非)字符并且非数字并且当前字符为-此时代表是负数
if ((index == 0 || (get_index(s[index - 1]) != 5&& get_index(s[index - 1]) != -2)) && s[index] == '-')
{
sign = -1;
index++;
}
else
{
char opt;
if (operation.empty())
{
opt = '<';
}
else opt= priority(operation.top(), s[index]);
//上一个操作符的优先级比当前操作符的大,需要将之前入栈的进行计算
if (opt == '>')
{
opt = operation.top();
operation.pop();
double num2 = number.top();
number.pop();
double num1 = number.top();
number.pop();
ans = cal(num1, opt, num2) * sign;
sign = 1;//避免对以后的结果符号造成影响
number.push(ans);
}
else if (opt == '=') //把括号删除
{
operation.pop();
index++;
}
else if (opt == '<')//小的话就把当前的入栈
{
operation.push(s[index]);
index++;
}
}
}
else
{
//把数字都先放进去
while (index < s.size() && get_index(s[index]) == -2)
{
num = num * 10 + s[index] - '0';
index++;
}
number.push(sign * num);
sign = 1;//避免对以后的造成影响
}
} while (!operation.empty());
cout << number.top();
return 0;
}