问题 L: 后缀表达式求值
题目描述
为了便于处理表达式,常常将普通表达式(称为中缀表示)转换为后缀{运算符在后,如X/Y写为XY/表达式。在这样的表示中可以不用括号即可确定求值的顺序,如:(P+Q)(R-S) → PQ+RS-。后缀表达式的处理过程如下:扫描后缀表达式,凡遇操作数则将之压进堆栈,遇运算符则从堆栈中弹出两个操作数进行该运算,将运算结果压栈,然后继续扫描,直到后缀表达式被扫描完毕为止,此时栈底元素即为该后缀表达式的值。
输入
输入一行表示后缀表达式,数与数之间一定有空格隔开(可能不只一个空格),最后输入@表示输入结束。
数据保证每一步的计算结果均为不超过100000的整数。
输出
输出一个整数,表示该表达式的值.
样例输入
14 3 20 5 / * 8 - + @
样例输出
18
解题过程
下面是对代码的详细解析:
-
头文件:
- 包含
<stdio.h>
头文件,提供输入输出函数。
- 包含
-
结构体定义:
STRACK
结构体用于模拟栈,包含一个数组m
用于存储栈中的元素,以及一个整型变量top
用于存储栈顶索引。
-
全局变量:
num
用于存储运算结果的临时变量。ch
用于存储输入的表达式字符串。
-
栈初始化:
Leng
是STRACK
类型的变量,用作栈,初始化top
为 -1,表示栈为空。
-
输入表达式:
- 使用
gets
函数读取一个以@
符号结尾的表达式。注意:gets
函数是不安全的,因为它可能导致缓冲区溢出。
- 使用
-
解析和运算:
- 使用
for
循环遍历表达式字符串ch
。 - 如果当前字符是数字,则将其转换为数值,并使用
while
循环读取多位数值,存储到栈Leng
中。 - 如果当前字符是运算符,则从栈中取出顶部两个数值,执行相应的运算,并将结果存回栈中,同时减少栈顶索引。
- 使用
-
输出结果:
- 使用
printf
函数输出栈顶元素,即表达式的计算结果。
- 使用
-
程序结束:
- 返回 0,表示程序正常结束。
代码逻辑分析:
- 这段代码使用了一个栈来存储表达式中的数值部分,遇到运算符时,从栈中取出两个数值进行运算,并将结果压回栈中。
- 它假设输入的表达式是有效的,并且运算符之后总是有数值。
潜在问题:
- 使用
gets
函数是不安全的,应该使用fgets
函数代替。 - 代码没有处理除以零的情况,这可能会导致运行时错误。
改进建议:
- 替换
gets
函数为fgets
,并添加对输入长度的检查。 - 添加对除以零情况的检查,并给出错误提示。
- 考虑增加对非法输入(如连续的运算符或不合法的字符)的检查。
- 可以使用更现代的字符串处理函数,如
sscanf
,来提高代码的可读性和健壮性。
二、部分代码
代码如下(定义结构体存储运算式):
typedef struct STRACK //定义结构体
{
double m[100];
int top;
} STRACK;
代码如下(利用while循环得到由多位由字符组成的数值):
if(ch[i]<='9'&&ch[i]>='0')
{
Leng.top++;
int temp=ch[i]-'0';
int j=i+1;
while(ch[j]!='@')
{
if(ch[j]<='9'&&ch[j]>='0')
{
temp=10*temp+(ch[j]-'0');
i++;
j++;
}
else break;
}
Leng.m[Leng.top]=temp;
}
代码如下( 遇到运算符进行计算):
else if(ch[i]=='+'||ch[i]=='-'||ch[i]=='*'||ch[i]=='/')
{
switch(ch[i])
{
case '+':
num=Leng.m[Leng.top-1]+Leng.m[Leng.top];
break;
case '-':
num=Leng.m[Leng.top-1]-Leng.m[Leng.top];
break;
case '*':
num=Leng.m[Leng.top-1]*Leng.m[Leng.top];
break;
case '/':
num=Leng.m[Leng.top-1]/Leng.m[Leng.top];
break;
}
Leng.m[Leng.top-1]=num; //往前一位存储前一步得到的结果
Leng.m[Leng.top]=0;
Leng.top--;
}
AC代码
#include<stdio.h>
typedef struct STRACK //定义结构体
{
double m[100];
int top;
} STRACK;
//定义结构体存储运算式
int main()
{
double num=0;
char ch[100];
STRACK Leng;
Leng.top=-1;
gets(ch);
for(int i=0; ch[i]!='@'; i++)
{
if(ch[i]<='9'&&ch[i]>='0')
{
Leng.top++;
int temp=ch[i]-'0';
int j=i+1;
while(ch[j]!='@') //利用while循环得到由多位由字符组成的数值
{
if(ch[j]<='9'&&ch[j]>='0')
{
temp=10*temp+(ch[j]-'0');
i++;
j++;
}
else break;
}
Leng.m[Leng.top]=temp;
}
else if(ch[i]=='+'||ch[i]=='-'||ch[i]=='*'||ch[i]=='/') //遇到运算符进行计算
{
switch(ch[i])
{
case '+':
num=Leng.m[Leng.top-1]+Leng.m[Leng.top];
break;
case '-':
num=Leng.m[Leng.top-1]-Leng.m[Leng.top];
break;
case '*':
num=Leng.m[Leng.top-1]*Leng.m[Leng.top];
break;
case '/':
num=Leng.m[Leng.top-1]/Leng.m[Leng.top];
break;
}
Leng.m[Leng.top-1]=num; //往前一位存储前一步得到的结果
Leng.m[Leng.top]=0;
Leng.top--;
}
}
printf("%.0lf",Leng.m[Leng.top]); //输出最后结果
return 0;
}