【c++】牛客 NC50999 表达式计算4(操作符栈+数字栈)非递归方式

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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

深|码|洞|悉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值