文章目录
一、表达式求值
表达式求值是程序设计语言编译的一个最基本的问题。它的实现是栈应用的又一典型例子。仅以算术表达式为例:
1.算术表达式的组成
将表达式视为由操作数、运算符、界限符(称为单词)组成。
【操作数】:常数、变量或符号常量。
【算符】:运算符、界限符。
2.算术表达式的形式
(1)中缀(infix)表达式——表达式的运算符在操作数的中间。即:<操作数><操作符><操作数>
例1:A*B
例2:5+9*7
(2)后缀(postfix)算术表达式(逆波兰式)——将运算符置两个操作数后面的算术表达式。即:<操作数><操作数><操作符>
例1:AB*
例2:597*+
(3)前缀(prefix)表达式(波兰式)又称波兰式,与后缀表达式相反。把运算符放在两个运算数的前面,即:<操作符><操作数><操作数>
例:*AB
例:+5*97
二、算术表达式的求值
【例】
中缀:1+(2-3)*4+4/2
后缀:123-4*+42/+
前缀:++1*-234/42
1、中缀表达式转后缀表达式
我们先讨论中缀表达式如何转后缀表达式,因为中缀表达式有利于人的理解运算,而后缀表达式更便于计算机的处理。
(1)限制考虑 +、-、*、/、() 符号,根据四则运算规则,我们可以得出其优先级(数字越大,优先级越高):
1:(
2:+ -
3:* /
4:)
对输入的中缀表达式从左到右遍历:
(1)如果遇到数字,直接添加到后缀表达式末尾;
(2)如果遇到运算符+、-、*、/:
先判断栈是否为空。若是,则直接将此运算符压入栈。若不是,则查看当前栈顶元素。若栈顶元素优先级大于或等于此操作符级别,则弹出栈顶元素,将栈顶元素添加到后缀表达式中,并继续进行上述判断。如果不满足上述判断或者栈为空,将这个运算符入栈。要注意的是,经过上述步骤,这个运算符最终一定会入栈。
(3)如果遇到括号:
如果是左括号,直接入栈。如果是右括号,弹出栈中第一个左括号前所有的操作符,并将左括号弹出。(右括号别入栈)。
(4)字符串遍历结束后,如果栈不为空,则弹出栈中所有元素,将它们添加到后缀表达式的末尾,直到栈为空。
#include <iostream>
#include <stack>
#include <string>
using namespace std;
//获取优先级
int getP(char ch){
if(ch == '(') return 1;
else if(ch == '+' || ch == '-') return 2;
else if(ch == '*' || ch == '/') return 3;
else return 4;
}
//将中缀表达式转化为后缀表达式
//默认输入是合法的
string getPE(string str){
stack<char> mystack;
int size = str.size();
int i = 0;
char tmp;
string res = ""; //存放中缀转化的后缀表达式
while(i < size){
//数字直接写入后缀
if(str[i] >= '0' && str[i] <= '9'){
res += str[i];
}
// 处理 + - * /
else if(str[i]=='+' || str[i]=='-' || str[i]=='*' || str[i]=='/'){
if(mystack.empty()) mystack.push(str[i]);//如果栈为空,直接入栈
else{
while(!mystack.empty()){
tmp = mystack.top();
if(getP(tmp) >= getP(str[i])){
res += tmp;
mystack.pop();
}
else break;
}
mystack.push(str[i]);
}
}
//处理括号 ()
else{
if(str[i]=='(') mystack.push(str[i]); //左括号直接入栈
else{
while(mystack.top() != '('){
tmp = mystack.top();
res += tmp;
mystack.pop();
}
mystack.pop();
}
}
i++;
}
//遍历完后,若栈非空,弹出所有元素
while(!mystack.empty()){
tmp