课程设计的内容和要求(包括原始数据、技术要求、工作要求等)
编写程序实现表达式求值,即验证某算术表达式的正确性,若正确,则计算该算术表达式的值。
主要功能描述如下:
1、从键盘上输入表达式。
2、分析该表达式是否合法:
(1)是数字,则判断该数字的合法性。若合法,则压入数据到堆栈中。
(2)是规定的运算符,则根据规则进行处理。在处理过程中,将计算该表达式的值。
(3)若是其它字符,则返回错误信息。
运算符优先级
对于连个相继出现的操作符θ1和θ2 有三种关系:大于、等于和小于。由此可以列出“+-*/”之间的优先级。如下表:
+ | - | * | / | ( | ) | # | |
+ | > | > | < | < | < | > | > |
- | > | > | < | < | < | > | > |
* | > | > | > | > | < | > | > |
/ | > | > | > | > | < | > | > |
( | < | < | < | < | < | = | |
) | > | > | > | > | > | > | |
# | < | < | < | < | < | = |
加减乘除优先性都低于“(”但是高于“)”,由运算从左到右可知,当θ1=θ2 ,令θ1>θ2
为了算法简洁,在表达式的左边和右边虚设一个“#”,这一对“#”表示一个表达式求值完成。
“(”=“)”当一对括号相遇时表示括号内已运算完成。
“)”和“(”、“#”和“(”、“(”和“#”无法相继出现如果出现则表达式出现语法错误。
为实现优先算法,可以使用两个工作栈,一个是OPTR,用于寄存运算符,一个是OPND,用于寄存运算数和运算结果。
首先置操作数栈为空栈,表达式起始符为“#”为栈底元素。
依次读入表达式中的每个字符,若是操作数则进OPND栈,若是运算符则和OPTR栈的栈顶运算符比较优先权作相应操作,直至整个表达式求值完毕(OPTR栈顶元素和当前读入的字符均为“#”)
👉 完整实现如下:
#include<stdio.h>
#include<cstdio>
#include<math.h>
#include<stdlib.h>
#include<stack>
using namespace std;
stack<double>opnd; //存储运算数
stack<char>optr; //存储运算符
char pre; //记录当前字符的前一个字符,用于负数的判断
int flag ; //值=1表示为负数,否则为正数
void init(){ //初始化
optr.push('#');
pre = '#';
flag = 0;
}
int IsNumber(char c){ //检查是否是数字
if(c >= '0' && c <= '9')return 1;
return 0;
}
int ErrorCheck(char c){ //返回1表示不是规定运算符
if(c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')' || c == '#')return 0;
return 1;
}
char Precede(char f,char l){ //运算级判断
if(f == '+' || f == '-'){
if(l == '*' || l == '/' || l == '(') return '<';
else return '>';
}
if(f == '*' || f == '/'){
if(l == '(') return '<';
else return '>';
}
if(f == '('){
if(l == ')') return '=';
else if(l!='#')return '<';
}
if(f ==')' && l !='(') return '>';
if(f == '#'){
if(l == '#') return '=';
else if(l!=')')return '<';
}
return '0';
}
double Compute(double b,char oper,double a){
if(oper == '-') return a-b;
if(oper == '+') return a+b;
if(oper == '*') return a*b;
if(oper == '/') return a/b;
}
int main(){
init();
char ch = getchar();
while(ch != '#' || optr.top() != '#'){
if(IsNumber(ch)){
double tot = 0;
do{
tot *= 10;
tot += (ch - '0');
pre = ch;
ch = getchar();
}while(IsNumber(ch));
if(ch == '.'){ //小数点后的数值
ch = getchar();
double tmp = 0.1;
while(IsNumber(ch)){
tot += (ch - '0')*tmp;
tmp *= 0.1;
pre = ch;
ch = getchar();
}
}
if(flag){
tot = 0 - tot;
flag = 0;
}
opnd.push(tot);
}else if(ch == '-' && (pre == '#' || pre == '(')){ //负数的判定
flag = 1;
ch = getchar();
}else {
if(ErrorCheck(ch)) {
printf("存在非规定的运算字符!\n");
return 0;
}
switch(Precede(optr.top(),ch)){
case '<' :{ //栈顶运算符优先级小
optr.push(ch);
pre = ch;
ch = getchar(); //重新接收下一个字符
break;
}
case '=' :{
optr.pop(); //出栈一对括号
pre = ch;
ch = getchar(); //重新接收下一个字符
break;
}
case '>' :{
char oper = optr.top();
optr.pop(); //出栈一个运算符
double a = opnd.top(); opnd.pop();
double b = opnd.top(); opnd.pop(); //出栈两个操作数
double tot = Compute(a,oper,b); //计算值,并将结果压入堆栈
opnd.push(tot);
break;
}
case '0':{
printf("表达式语法错误,括号不匹配!\n");
return 0;
break;
}
} //switch
} //else
} //while
printf("%.2lf\n",opnd.top());
opnd.pop();
return 0;
}
✅ 输入形式如:
2+(-2+10)*5/2# 以#号结尾