使用逆波兰式进行表达式求值
Posted llguanli
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用逆波兰式进行表达式求值相关的知识,希望对你有一定的参考价值。
中缀表达式及后缀表达式图解中说明了使用逆波兰式进行表达式求值的方法。这里使用C++进行实现。实现和原理解说有一点不同,须要进一步进行细化。
关于将中缀表达式转换成后后缀表达式的规则:
规则:从左到右遍历中缀表达式的每一个数字和符号,若是数字就输出。即成为后缀表达式的一部分;若是符号。则推断其与栈顶符号的优先级。是右括号或优先级低于找顶符号(乘除优先加减)则栈顶元素依次出找并输出,并将当前符号进栈,一直到终于输出后缀表达式为止。
上面的规则转换成以下的运行规则:
1.遇到操作数:直接输出(加入到后缀表达式中)
2.栈为空时,遇到运算符。直接入栈
3.遇到左括号:将其入栈
4.遇到右括号:运行出栈操作,并将出栈的元素输出,直到弹出栈的是左括号。左括号不输出。
5.遇到其它运算符:加减乘除:弹出全部优先级大于或者等于该运算符的栈顶元素。然后将该运算符入栈
6.终于将栈中的元素依次出栈,输出。
须要在流程中对上面6种情况下进行推断并作对应的处理。而且因为数字可能有多位,所以对操作数的取值也是一个问题。
//比較lhs的优先级是否不高于rhs。rhs表示栈顶的符号 bool priority(char lhs,char rhs) { if (rhs==‘(‘) return false; if (lhs==‘+‘||lhs==‘-‘) return true; if ((lhs==‘*‘||lhs==‘/‘)&&(rhs==‘*‘||rhs==‘/‘)) return true; return false; } //将中缀表达式转换成后缀式 string inPrefix2postPrefix(string str) { string res;//后缀表达式结果 stack<char> s; for (int i=0;i<str.size();i++) { //假设是数字,直接增加后缀表达式结果中 if (isdigit(str[i])) { while (i<str.size()&&isdigit(str[i])) { res+=str[i]; i++; } i--;//注意这里要将i减1。由于上面的循环将i多右移了一位。假设不减1,会漏掉一位 res+=" "; } else //假设是符号,须要与栈顶的元素进行比較 { //假设栈为空。将其直接压入栈中;假设是左括号(。也直接将其压入栈中 if (s.empty()||str[i]==‘(‘) s.push(str[i]); else { //当碰到右括号时。将栈中的数据出栈,直到碰到左括号。注意左右括号都不须要增加结果res中 if (str[i]==‘)‘) { while (!s.empty()&&s.top()!=‘(‘)//注意在对栈运行top操作之前须要推断栈是否为空 { res+=s.top(); res+=" "; s.pop(); } s.pop(); } else { //此时表示该字符为符号,而且不为‘(‘和‘)‘ if (priority(str[i],s.top()))//假设它的优先级不高于栈顶符号,那么将栈顶符号出栈 { while(!s.empty()&&priority(str[i],s.top())) { res+=s.top(); res+=" "; s.pop(); } s.push(str[i]);//最后记得将该符号入栈 } else //假设它的优先级比栈顶符号高,那么直接入栈 s.push(str[i]); } } } } while(!s.empty())//遍历完字符串后将栈中剩余的元素增加结果集中 { res+=s.top(); res+=" "; s.pop(); } return res; }
int operate(int first,int second,char op) { int res=0; switch (op) { case ‘+‘: res= first+second; break; case ‘-‘: res=first-second; break; case ‘*‘: res=first*second; break; case ‘/‘: res=first/second; break; default: break; } return res; } int calculateByPostPrefix(string input) { stack<int> s; int tmp=0; for (int i=0;i<input.size();i++) { if (isdigit(input[i]))//假设遇到的是数字。就将数字入栈 { while(i<input.size()&&isdigit(input[i])) { tmp=10*tmp+input[i]-‘0‘; i++; } //得到数字以后将这个输入压入栈中 s.push(tmp); i--; } else if(input[i]==‘ ‘)//假设遇到空格,就将tmp重置为0 tmp=0; else//此时遇到的就是符号 { //取出两个操作数。并进行计算 int second=s.top(); s.pop(); int first=s.top(); s.pop(); int local=operate(first,second,input[i]); s.push(local); } } return s.empty()?0:s.top(); }
主函数例如以下:
int main() { string str;//9+(3-1)*3+10/2 cout<<"请输入合法的表达式(支持整数的+,-,*,/,括号运算):"<<endl; while(getline(cin,str)) { string ot=inPrefix2postPrefix(str); cout<<"后缀表达式为:"<<ot<<endl; cout<<"计算结果为:"<<calculateByPostPrefix(ot)<<endl; cout<<"请输入表达式:"<<endl; } system("pause"); return 0; }
取前一篇文章中的样例“9+(3-1)*3+10/2”进行測试,查看转换后的后缀表达式以及运算结果,程序支持在控制台中持续输入几组数据并计算结果。
完整的代码:下载
以上是关于使用逆波兰式进行表达式求值的主要内容,如果未能解决你的问题,请参考以下文章