【背景】
表达式的表示形式有:中缀、前缀和后缀3种形式
【概念】
后缀表达式中,只有操作数(1.2.3....)和操作符(+,-,*,/)
--- 换句话说,就是没有所谓的小括号之类的。
操作符在两个操作数之后。
例如:平时我们习惯是2+1;写成后缀表达式,就变成了:21+
【规则】
每遇到一个操作符,就将前面的两个数执行相应的操作。
【存在的意义】
计算机求值问题,用后缀表达式处理,是比较方便的。
【颠覆世界观的例子】
中缀表达式:0.3/(5*2+1)#
等价后缀表达式:0.3
5 2 * 1 + /#
【中缀表达式转换为等价的后缀表达式原理】 --- 比较复杂,我自己也没明白
(1)从左到右依次扫描中缀表达式的每一个字符,如果是数字字符和圆点“.”则直接将它们写入后缀表达式中。
(2)如果遇到的是开括号“(”,则将它们压入一个操作符栈(不需要与栈顶操作符相比较),它表明一个新的计算层次的开始,
在遇到和它匹配的闭括号“)”时,将栈中的元素弹出来并放入后缀表达式中,
直到栈顶元素为“(”时,将栈顶元素“(”弹出(不需要加入后缀表达式),表明这一层括号内的操作处理完毕。
(3)如果遇到的是操作符,则将该操作符和操作符栈顶元素比较:
1、当所遇到的操作符的优先级小于或等于栈顶元素的优先级时,
则取 出栈顶元素放入后缀表达式,并弹出该栈顶元素,反复执行直到当前操作符的优先级大于栈顶元素的优先级小于;
2、当所遇到的操作符的优先级大于栈顶元素的优先级的时则将它压入栈中。
(4)重复上述步骤直到遇到中缀表达式的结束符标记“#”,弹出栈中的所有元素并放入后缀表达式中,转换结束【C++代码】
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<vector>
#include<stack>
#include<algorithm>
using namespace std;
int pre(char a) //操作符优先级比较
{
if(a == '=' || a == '(')
return 0;
else if(a == '+' || a == '-')
return 1;
else if(a == '*' || a == '/')
return 2;
}
int main()
{
int ncase, len;
string str;
char tmp;
stack<char> ope; //操作符
vector<char> ans;//后缀表达式
vector<char>::iterator start, end;
scanf("%d", &ncase);
getchar(); //清除输入垃圾
while(ncase--)
{
while(!ope.empty()) //初始化
ope.pop();
ans.clear();
ope.push('='); //结束标志
cin>>str;
len = str.length();
for(int i = 0 ; i < len; ++i)
{
if(str[i] >= '0' && str[i] <= '9') //操作数直接存入ans
ans.push_back(str[i]);
else if(str[i] == '(') //左括号入栈
ope.push(str[i]);
else if(str[i] == ')') //右括号,将匹配的左括号内容存入ans,左括号出栈
{
while (ope.top() != '(')
{
ans.push_back(ope.top());
ope.pop();
}
ope.pop(); //左括号出栈
}
else if(pre(str[i]) > pre(ope.top())) //优先级大于栈顶元素则入栈
ope.push(str[i]);
else //小于栈顶元素
{
while(pre(str[i]) <= pre(ope.top()))
{
ans.push_back(ope.top());
ope.pop();
}
ope.push(str[i]);
}
}
while(ope.top() != '=') //其余操作符存入后缀表达式中
{
ans.push_back(ope.top());
ope.pop();
}
for(start = ans.begin(), end = ans.end(); start < end; ++start)
printf("%c", *start);
printf("\n");
}
return 0;
}