算术四则运算遵循以下 3条规则:
(1)先乘除,后加减;(2)从左算到右;(3)先括号内,后括号外。
θ₁ \ θ₂ |
+
| - | * | / | ( | ) | # |
+ | > | > | < | < | < | > | > |
- | > | > | < | < | < | > | > |
* | > | > | > | > | < | > | > |
/ | > | > | > | > | < | > | > |
( | < | < | < | < | < | = | |
) | > | > | > | > | > | > | |
# | < | < | < | < | < | = |
由规则(1),先进行乘除运算,后进行加减运算,所以有“ + ” < “ * ”;“ + ” < “ / ”;“ * ” > “ + ”;“ / ” > “ + ”等。
由规则(2),运算遵循左结合性,当两个运算符相同时,先出现的运算符优先级高,所以有“ + ” > “ + ” ; “ — ” > “ — ”; “ * ” > “ * ” ; “ / ” > “ / ” 。
由规则(3),括号内的优先级高,+、—、*和/为θ₁时的优先性均低于“ ( ”但高于“ ) "。
表中的“(”=“)”表示当左右括号相遇时,括号内的运算已经完成。为了便于实现,假设每个表达式均以“#”开始,以“#”结束。所以“#”=“#”表示整个表达式求值完毕。")”与“(”、“#”与“)”以及“(”与“#”之间无优先关系,这是因为表达式中不允许它们相继出现,一旦遇到这种情况,则可以认为出现了语法错误。
算法步骤:
①初始化OPTR栈和OPND栈,将表达式起始符“#”压入OPTR栈。
②扫描表达式,读入第一个字符ch,如果表达式没有扫描完毕至“#”或OPTR的栈顶元素不为“#”时,则循环执行以下操作:
●若ch不是运算符,则压入OPND栈,读入下一字符ch;
●·若ch是运算符,则根据OPTR 的栈顶元素和ch的优先级比较结果,做不同的处理;
>若是小于,则ch 压入 OPTR栈,读人下一字符ch;
>若是大于,则弹出OPTR栈顶的运算符,从OPND栈弹出两个数,进行相应运算,结果压入OPND栈;
>若是等于,则OPTR的栈顶元素是“(”且ch是“)”,这时弹出OPTR栈顶的“(”,相当于括号匹配成功,然后读入下一字符ch。
③OPND栈顶元素即为表达式求值结果,返回此元素。
具体实现:
#include <iostream>
#include<stack>//调用(STL stack)容器
#define OK 1
#define ERROR -1
#define OVERFLOW -2
using namespace std;
//判断输入的字符ch是否是运算符
bool In(char ch){
if( ch=='+' || ch=='-' || ch=='*' || ch=='/' || ch=='(' || ch==')' || ch=='#' ){
return true;
}
else return false;
}
//判定运算符栈(OPTR)的栈顶元素与读入的运算符之间优先关系
char Precede(char ch1,char ch2){
if( ch1 =='+' || ch1 =='-' ){//判断第一个运算符
if( ch2 =='*' || ch2 =='/' || ch2 =='(' ){//判断第二个运算符
return '<';
}
else return '>';
}
else if( ch1 =='*' || ch1 =='/'){
if( ch2 =='(' ){
return '<';
}
else return '>';
}
else if( ch1 =='(' ){
if( ch2 ==')' ){
return '=';
}
else if( ch2 =='#'){
return '?';//出错
}
else return '<';
}
else if( ch1 ==')' ){
if( ch2 =='('){
return '?';//出错
}
else return '>';
}
else if( ch1 =='#' ){
if( ch2 =='#' ){
return '=';
}
else if( ch2 == ')' ){
return '?';
}
else return '<';
}
else return '?';//其他的都return错误
}
//进行二元运算的函数
int Operate(int a,char theta,int b){
if(theta == '+' )
return a+b;
else if(theta == '-')
return a-b;
else if(theta == '*')
return a*b;
else if(theta == '/')
return a/b;
else return 0;
}
int CALCULATE(){
stack<int> OPND;//运算数栈
stack<char> OPTR;//运算符栈
OPTR.push('#');//表达式起始"#"压入OPTR栈
char ch;
char theta;
int a,b,num=0;
cin >> ch;
/* 当表达式没有扫描完毕至表达式末尾的"#"
或OPTR(操作符栈)的栈顶元素不是"#"(他目前栈底元素是"#")时进入循环 */
while(ch != '#' || OPTR.top()!='#'){
if(!In(ch)){//若ch不是运算符,则压入OPND(操作数)栈,读入下一个字符ch
num=num*10+(ch-'0');//0的ASCII码是48
cin >> ch;
if(In(ch)) {
OPND.push(num);
num =0;
}
}
else//若ch是运算符
{
switch (Precede(OPTR.top(),ch)){//比较OPTR(运算符)的栈顶元素和ch的优先级
case '<':
OPTR.push(ch);//当前字符ch压入OPTR(运算符)栈,读入下一个字符ch
cin >> ch;
break;
case '>':
theta = OPTR.top(); OPTR.pop();//弹出OPTR(运算符)栈顶元素符
b = OPND.top(); OPND.pop();//弹出OPND(操作数)栈顶的两个运算数
a = OPND.top(); OPND.pop();
OPND.push(Operate(a,theta,b));//将运算结果压入OPND(操作数)栈
break;
case '='://"="只有一种情况,OPTR(操作数)的栈顶元素是"("且ch是")"
OPTR.pop();//弹出OPTR(操作数)栈顶的"(",消去一对括号,读入下一字符ch
cin >> ch;
break;
default:
exit(ERROR);
}
}
}
cout << OPND.top();//求值结果
return 0;
}
int main(){
CALCULATE();
}