PTA 6 后缀表达式计算 (100 分)

Kunkun学长觉得应该让学弟学妹了解一下这个知识点:后缀表达式相对于中缀表达式更容易让计算机理解和学习。现在kunkun学长给出一串后缀表达式,你能帮他算出这个后缀表达式的值吗?

输入格式:

第一行输入后缀表达式长度n(1<=n<=25000);

第二行输入一个字符串表示后缀表达式(每个数据或者符号之间用逗号隔开,保证输入的后缀表达式合法,每个数包括中间结果保证不超过long long长整型范围)

输出格式:

输出一个整数,即后缀表达式的值。

输入样例1:

6
10,2,+

输出样例1:

12

输入样例2:

14
2,10,2,+,6,/,-

输出样例2:

0

代码(最终):

#include<stdio.h>
#include<string.h>
#include<math.h>


int sum_or_sub(long long stack[], int top, int type) 
// 负责加减运算 type 参数:1为加, -1为减
{
    stack[top - 2] += stack[top - 1] * type;
    stack[top - 1] = 0;  // 这里要删除掉 栈顶 的值!!!
    return top - 1; // 返回top,由top接收。栈顶退一格
}


int mul_or_div(long long stack[], int top, int type)
// 负责乘除运算 1为乘, -1(其他)除
{
    if (type == 1) stack[top - 2] *= stack[top - 1];
    else stack[top - 2] /= stack[top - 1];
    stack[top - 1] = 0;
    return top - 1;
}


int main()
{
    int len, top = 0, flag = 1;
    // len就是字符串长度, top为栈顶, flag在后面做判断正负数用
    char str[25001];
    long long stack[10000];
    scanf("%d %s",&len, str);

    for (int i = 0; i < len; i++)
    {
        switch (str[i])
        {
            // 遇到加乘除可以直接运算的
            case '+': top = sum_or_sub(stack, top, 1); break;
            case '*': top = mul_or_div(stack, top, 1); break;
            case '/': top = mul_or_div(stack, top, -1); break;
            case ',': continue;  // 逗号是分界符
            default:  // 剩下的情况就是本次读取到的字符是 ‘-’或数字了
            {
                // 如果‘-’的后面是数字,那么这个‘-’应该是负号,能与接下来的数字组合。
                // 让flag变为-1
                if (str[i] == '-' && '0' <= str[i+1] && str[i+1] <= '9') flag = -1;
                
                // 如果‘-’后面是逗号或者‘-’是最后一个字符,那么应该为减号,执行减法运算
                else if (str[i] == '-' && (str[i+1] == ',' || i+1 == len)) top = sum_or_sub(stack, top, -1);
                
                // 再者就是数字的情况了。
                else
                {
                    // 这一步是读取运算数的核心
                    // 但是正因为使用了这样的方式,得在负责运算的函数中多加清空栈顶数据的操作。
                    // 如果只有退一格栈的话会出bug
                    while (str[i]!=',')  {stack[top] = stack[top] * 10 + str[i++] - '0';}
                    // flag默认为1,如果前面有负号(第一个if判断得出的),那么存到栈里的结果就是负数。
                    stack[top++] *= flag;
                    flag = 1;  // 初始化flag
                }
            }
        }
    }
    printf("%lld", stack[top - 1]);
    return 0;
}

总结:

        这个运算法则就不细讲了,就是读到数字存栈里,读到运算符就拿栈顶和栈顶下面那个运算一下就行。注意下被减数和减数,被除数和除数的先后顺序(栈顶的是减/除数!)就行了。

        这个题我做了两遍,第一遍就差一个点AC,非常难受。最后发现了这道题的坑点处在对于 ‘-’ 的处理上。‘-’ 有两种情况,分别是 负号 和 减号。也就是说运算数可能是负数。。。

        这里给出我第一遍的代码:

#include<stdio.h>
#include<string.h>
#include<math.h>


long long turn_str_to_lld(int num[])  // 转化数组到lonnglong
{
    long long ans = 0;
    int max = num[0];
    for (int i = 1; i <= max; i++)
    {
        ans += pow(10, --num[0]) * num[i];
    }
    return ans;
}


int sum_or_sub(long long stack[], int top, int type) // 1为加, -1为减
{
    stack[top - 2] += stack[top - 1] * type;
    return top - 1; // 返回top,由top接收
}


int mul_or_div(long long stack[], int top, int type)// 1为乘, -1(其他)除
{
    if (type == 1) stack[top - 2] *= stack[top - 1];
    else stack[top - 2] /= stack[top - 1];
    return top - 1;
}


int main()
{
    int len;    scanf("%d", &len);
    char str[len];  memset(str, 0, sizeof(str));    scanf("%s", str);

    int top = 0;    long long stack[30000];

    int num[20] = {0};

    for (int i = 0, j = 1; i < len; i++)
    {
        switch (str[i])
        {
            case '+': top = sum_or_sub(stack, top, 1); break;
            case '-': top = sum_or_sub(stack, top, -1); break;
            case '*': top = mul_or_div(stack, top, 1); break;
            case '/': top = mul_or_div(stack, top, -1); break;
            case ',': continue;
            default:
            {
                num[j++] = str[i] - '0';  num[0]++;
                if (str[i+1] == ',')
                {
                    j = 1;
                    stack[top++] = turn_str_to_lld(num);
                }
            }
        }
    }
    printf("%lld", stack[top - 1]);
    return 0;
}

        我的第一版读取数字的方法比较麻烦(我也不知道当时为什么会这么写),先用一个数组依次存储运算数的每一位,再用一个函数转化成longlong存入栈里。

        后来我发现坑点之后,发现这段要改起来要多写一坨玩意,得把自己绕晕咯。所以果断把读取数字的方法重写了一遍,具体为:

                   循环 {栈顶的数据*10(进一位) + 当前读取到的数字 } 直到读取到 ‘,’

        但这要求第一次的栈顶必须得是0,所以退栈需要给栈顶先赋值为0再让指向栈顶的top--。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值