看前须知
第四次上机题汇总
BUAA(2021春)文本编辑操作模拟(简)a——介绍两种方法.
BUAA(2021春)银行排队模拟(生产者-消费者模拟)——理解题意有点小难.
题目内容
问题描述
从标准输入中读入一个整数算术运算表达式,如24 / ( 1 + 5%3 + 36 / 6 / 2 - 2) * ( 12 / 2 / 2 )= ,计算表达式结果,并输出。
要求:
-
表达式运算符只有+、-、*、/、%,表达式末尾的=字符表示表达式输入结束,表达式中可能会出现空格;
-
表达式中会出现圆括号,括号可能嵌套,不会出现错误的表达式;
-
出现除号/时,以整数相除进行运算,结果仍为整数,例如:5/3结果应为1。
-
要求采用逆波兰表达式来实现表达式计算。
输入形式
从键盘输入一个以=结尾的整数算术运算表达式。操作符和操作数之间可以有空格分隔。
输出形式
在屏幕上输出计算结果(为整数,即在计算过程中除法为整除)。
样例
输入
24 / ( 1 + 5%3 + 36 / 6 / 2 - 2) * ( 12 / 2 / 2 ) =
输出
18
样例说明
按照运算符及括号优先级依次计算表达式的值。
题解
易错点和难点
本题就是在考察同学对于栈的使用。本题有两个思路,一个是把中缀表达式转换为后缀表达式(逆波兰式),再进行计算;另一种是再中缀表达式通过栈转化为后缀表达式的过程中就把表达式计算完(笔者采用的就是这种方法)。本题需要维护两个栈,一个运算符栈,一个是操作数(数字)栈,通过频繁地入栈和出栈完成目的。
本题最难的部分在于怎么处理运算符的优先级,对于这个问题,笔者也是有一段时间思考过怎么不用动脑子的解决这个问题,最后发现不用动脑子的方法的就是把运算符的优先级表打出来(《数据结构教程(第3版)》 唐发根 北京航空航天大学出版社 的栈的应用部分,里面有具体介绍符号的优先级的大小比较和优先级表),打出优先级表之后,这道题简直就是有手就行。
参考代码
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<ctype.h>
#define MAXSIZE 100
typedef int ElemType;
struct stack{
int Top;
ElemType data[MAXSIZE];
};
typedef struct stack Stack;
typedef struct stack *Stackp;
Stack OPFIGURE,OPTHETA;
void push( Stackp s, ElemType item )
{
s->data[++s->Top]=item;
}
int pop( Stackp s)
{
return s->data[s->Top--];
}
int Gettop( Stackp s )
{
return s->data[s->Top];
}
char Pre(char theta1,char theta2)//运算符优先级比较
{
int i,j;
char pre[8][8]={// + - * / ( ) = %
{'>','>','<','<','<','>','>','<'},
{'>','>','<','<','<','>','>','<'},
{'>','>','>','>','<','>','>','>'},
{'>','>','>','>','<','>','>','>'},
{'<','<','<','<','<','=','0','<'},
{'>','>','>','>','0','>','>','>'},
{'<','<','<','<','<','0','=','<'},
{'>','>','>','>','<','>','>','>'},};
switch(theta1){
case '+': i=0; break;
case '-': i=1; break;
case '*': i=2; break;
case '/': i=3; break;
case '(': i=4; break;
case ')': i=5; break;
case '=': i=6; break;
case '%': i=7; break;
}
switch(theta2){
case '+': j=0; break;
case '-': j=1; break;
case '*': j=2; break;
case '/': j=3; break;
case '(': j=4; break;
case ')': j=5; break;
case '=': j=6; break;
case '%': j=7; break;
}
return(pre[i][j]);
}
int Op(int a,char theta,int b)//运算符含义表达
{
int result;
switch(theta){
case'+':return a+b;
case'-':return a-b;
case'*':return a*b;
case'%':return a%b;
case'/': //判断除数是否为0,若除数为零返回错误提示
if(b!=0)
return a/b;
else
{
exit(0);
}
}
}
int IsTheta(char c) //判断是否为运算符,是运算符返回1,若不是返回0
{
switch(c){
case '+':
case '-':
case '*':
case '/':
case '(':
case ')':
case '%':
case '=':
return 1;
default:
return 0;
}
}
int EvaluateExpression(char *expression) //表达式运算
{
ElemType a,b,theta,tmp,X1,X2;
char ch;
int i=0;
OPFIGURE.Top=-1;
OPTHETA.Top=-1;
push(&OPTHETA,'='); //把 = 压入运算符栈
ch=expression[i++]; // ch 读取表达式的下一个字符
while(ch!='=' || Gettop(&OPTHETA)!='=')
{
if(IsTheta(ch)) //判断是否为运算符
{
switch(Pre(Gettop(&OPTHETA),ch)) // 比较 ch 和栈顶运算符 OPTHETA.data 的优先级
{
case'<':
push(&OPTHETA,ch);
ch=expression[i++];
break;
case'>':
theta=pop(&OPTHETA);
b=pop(&OPFIGURE);
a=pop(&OPFIGURE);
push(&OPFIGURE,Op(a,theta,b));
break;
case'=':
tmp=pop(&OPTHETA);
ch=expression[i++]; //读取下一位字符并将指针向后偏移一位
break;
}
}
else if(isdigit(ch)) //判断是否为数字
{
X1=ch-'0'; //将字符形式转化为数字
push(&OPFIGURE,X1);
X2=X1;
ch=expression[i++]; //读取下一位字符并将指针向后偏移一位
while(isdigit(ch)) //判断下一位是否还是数字
{
X1=ch-'0';
X2=10*X2+X1; //归并至X2
tmp=pop(&OPFIGURE);
push(&OPFIGURE,X2);
ch=expression[i++]; //读取下一位字符并将指针向后偏移一位
}
}
else if(ch==' ') //判断是否为空格
{
while(ch==' ')
{
ch=expression[i++];
}
}
else //出现非法字符
{
exit(0);
}
}
return(Gettop(&OPFIGURE));
}
int main()
{
char expression[100];
int result;
gets(expression);
result=EvaluateExpression(expression);
printf("%d\n",result);
return 0;
}
补充测试的数据
输入
1=
输出
1
输入
1+(8/9+8)*(5*7+6)/(4+8)=
输出
28
输入
(1+3+4*5*(36/9+37))/(7+81/10+3*6)=
输出
24
题单链接
有考虑过负数和乘方怎么解决吗好兄弟