G
N
I
D
A
O
L

【数据结构-栈】栈在表达式求值的应用

前缀、中缀、后缀表达式的互相转换

  • 前缀表达式:也称波兰式,指运算符处于两个操作数的前面
  • 中缀表达式:指运算符在两个操作数之间的位置
  • 后缀表达式:也称逆波兰式,指运算符处于两操作数后面

【例 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+
posted @ 2022-07-26 17:05  漫舞八月(Mount256)  阅读(141)  评论(0编辑  收藏  举报