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--。