【数据结构-栈】栈在表达式求值的应用
前缀、中缀、后缀表达式的互相转换
- 前缀表达式:也称波兰式,指运算符处于两个操作数的前面
- 中缀表达式:指运算符在两个操作数之间的位置
- 后缀表达式:也称逆波兰式,指运算符处于两操作数后面
【例 1】已知中缀表达式:a+b-c*d
- 先确定运算顺序:
(a+b)-(c*d)
- 前缀表达式:
- +ab *cd
- 后缀表达式:
ab+ cd* -
【例 2】已知中缀表达式:a/b+(c*d-e*f)/g
- 先确定运算顺序:
(a/b)+(((c*d)-(e*f))/g)
- 前缀表达式:
+ /ab / -*cd *ef g
- 后缀表达式:
ab/ cd* ef*- g/ +
中缀表达式转后缀表达式的算法
- 扫描到数字:直接加入后缀表达式;
- 扫描到“(”:入栈;
- 扫描到“)”:依次把栈中的运算符加入后缀表达式,直到出现“(”,丢弃“(”;
- 扫描到运算符:(1)如果当前运算符优先级大于栈顶运算符,当前运算符直接入栈;(2)如果当前运算符优先级小于等于栈顶运算符,需要弹出当前运算符优先级小于等于栈顶的运算符,直到栈空或遇到栈顶为左括号,最后当前运算符入栈。
#include <iostream>
#include <string>
#include <stack>
using namespace std;
// 栈外优先级 (in coming priority)
int icp (const char c)
{
switch (c)
{
case '+':
case '-':
return 0; // 低优先级运算符
case '*':
case '/':
return 1; // 高优先级运算符
default:
return -1;
}
}
// 中缀表达式转化为后缀表达式
string Mid2RPN (const string s)
{
stack<char> opStack; // 定义运算符栈
int length = s.length();
int op_num;
string result = ""; // 后缀表达式
for (int i = 0; i < length; i++)
{
cout << "当前扫描:" << s[i];
switch (s[i])
{
case '+':
case '-':
case '*':
case '/':
if ( opStack.empty() || (icp(s[i]) > icp(opStack.top())) ) // 如果 当前运算符优先级 大于 栈顶运算符
{
opStack.push(s[i]); // 当前运算符 压入栈
}
else // 如果 当前运算符优先级 小于等于 栈顶运算符
{ // 需要弹出 当前运算符优先级 小于等于 栈顶的运算符,直到 栈空 或遇到 栈顶为左括号
while ( !opStack.empty() && ( (opStack.top() != '(') || (icp(s[i]) <= icp(opStack.top())) ) )
{
result += opStack.top(); // 栈中优先级小或相同的运算符 出栈
opStack.pop();
}
opStack.push(s[i]); // 弹出 栈中优先级小或相同的运算符 后,当前运算符 入栈
}
break;
case '(':
opStack.push(s[i]); // 压入 左括号
break;
case ')':
while ( !opStack.empty() && opStack.top() != '(' ) // 把栈中的运算符弹出,直到遇到左括号
{
result += opStack.top(); // 弹出 栈中的运算符
opStack.pop();
}
opStack.pop(); // 弹出 左括号
break;
default:
result += s[i];
break;
}
// 每处理完一个元素,打印中间处理过程,方便观察
if (!opStack.empty())
cout << " 当前栈顶:" << opStack.top();
else
cout << " 当前栈顶:#";
cout << " 当前后缀表达式:" << result <<endl;
}
// 栈中剩余的运算符依次出栈
while (!opStack.empty())
{
result += opStack.top();
opStack.pop();
}
return result;
}
int main()
{
string s, result;
//s = "a/b+(c*d-e*f)/g";
s = "a+b-a*((c+d)/e-f)+g";
cout << "中缀表达式:" << s << endl;
result = Mid2RPN(s);
cout << "最终后缀表达式:" << result << endl;
return 0;
}
输出结果参考:
中缀表达式:a+b-a*((c+d)/e-f)+g
当前扫描:a 当前栈顶:# 当前后缀表达式:a
当前扫描:+ 当前栈顶:+ 当前后缀表达式:a
当前扫描:b 当前栈顶:+ 当前后缀表达式:ab
当前扫描:- 当前栈顶:- 当前后缀表达式:ab+
当前扫描:a 当前栈顶:- 当前后缀表达式:ab+a
当前扫描:* 当前栈顶:* 当前后缀表达式:ab+a
当前扫描:( 当前栈顶:( 当前后缀表达式:ab+a
当前扫描:( 当前栈顶:( 当前后缀表达式:ab+a
当前扫描:c 当前栈顶:( 当前后缀表达式:ab+ac
当前扫描:+ 当前栈顶:+ 当前后缀表达式:ab+ac
当前扫描:d 当前栈顶:+ 当前后缀表达式:ab+acd
当前扫描:) 当前栈顶:( 当前后缀表达式:ab+acd+
当前扫描:/ 当前栈顶:/ 当前后缀表达式:ab+acd+
当前扫描:e 当前栈顶:/ 当前后缀表达式:ab+acd+e
当前扫描:- 当前栈顶:- 当前后缀表达式:ab+acd+e/
当前扫描:f 当前栈顶:- 当前后缀表达式:ab+acd+e/f
当前扫描:) 当前栈顶:* 当前后缀表达式:ab+acd+e/f-
当前扫描:+ 当前栈顶:+ 当前后缀表达式:ab+acd+e/f-*-
当前扫描:g 当前栈顶:+ 当前后缀表达式:ab+acd+e/f-*-g
最终后缀表达式:ab+acd+e/f-*-g+