背景
中缀表达式,运算符在操作数的中间,即一般的表达式;
后缀表达式,运算符在操作数的后面;
前缀表达式,运算符在操作数之前.
下面我们实现由一般的中缀表达式到后缀表达式的转换.
手算
举例说明: a+b*c+(d*e+f)*g
- 将其按照先乘除后加减以及从左到右的原则添加上括号
((a + (b * c)) + (((d * e) + f) * g))
,熟练了该步可以省去,添加括号反而增加麻烦.
- 根据括号由内向外将表达式转换为后缀形式
a bc* + de* f+ g* +
.
得到最终结果,但此法不适用于计算机.
但我们可以从中看出一些规律,这对设计计算机算法有所裨益.
例如:
- 操作数之间的相对顺序并未改变.
- 内层的运算符总是比外层的运算符先输出.
a+b*c
中*
要先运算;而a*b+c...
中也是*
先运算,但到+
时意味着前面的运算已经影响不到后面的运算了(除非有括号),也就是说在没有括号参与的情况下,低运算级(+,-)前面的高运算级(+,-,*,/)可以输出了.
- 接上条,在括号内部的运算总是优先的,于是我们可以将右括号
)
视为一个括号运算的结束,那么怎么找到与之对应的左括号呢?我们很自然的想到括号匹配问题中使用的栈.
基于以上几条我们可以设计一个适用于计算机的转换算法.
机算
算法思想:
1 2 3
| 1. 遇到操作数直接输出; 2. 遇到左括号'('进栈,直到遇到右括号')'代表该括号内已经运算完毕, 直接一个个输出栈内元素直到匹配到'('或者栈空. 3. 遇到运算符, 如果是 +,- 则其前面的 +,-,*,/ 已经运算完毕, 全部输出直到栈空或者遇到'('; 如果是 *,/ 则后面可能还有运算, 应该将其先入栈. 这里 +,-,*,/ 也可用优先级表示.
|
实际运算:
- 遇到
a
,输出.
输出: a
栈:
- 遇到
+
,入栈.
输出: a
栈: +
- 遇到
b
,输出.
输出: ab
栈: +
- 遇到
*
,优先级比栈顶元素高,入栈.
输出: ab
栈: +-
- 遇到
c
,输出.
输出: abc
栈: +*
- 遇到
+
,优先级比栈顶低,输出栈直到空或’(',最后当前运算符入栈.
输出: abc*+
栈: +
- 遇到
(
,入栈.
输出: abc*+
栈: +(
- 遇到
d
,输出.
输出: abc*+d
栈: +(
- 遇到
*
,栈顶’(',故入栈.
输出: abc*+d
栈: +(*
- 遇到
e
,输出.
输出: abc*+de
栈: +(*
- 遇到
+
,输出栈直到空或者’(',最后当前运算符入栈.
输出: abc*+de*
栈: +(+
- 遇到
f
,输出.
输出: abc*+de*f
栈: +(+
- 遇到
)
,输出直到匹配到左括号,括号不输出.
输出: abc*+de*f+
栈: +
- 遇到
*
,优先级高,入栈.
输出: abc*+de*f+
栈: +*
- 遇到
g
,输出.
输出: abc*+de*f+g
栈: +*
- 遍历完,输出所有栈内元素.
输出: abc*+de*f+g*+
栈:
完成,结果为abc*+de*f+g*+
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
| #include <map> #include <set> #include <ctime> #include <stack> #include <cmath> #include <queue> #include <bitset> #include <string> #include <vector> #include <cstdio> #include <cctype> #include <fstream> #include <cstdlib> #include <sstream> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define LL long long #define up(x) for(int i=0;i<x;i++) #define rson mid+1,r,rt<<1|1 #define lson l,mid,rt<<1
const int INF = 0x3f3f3f3f; const int negative_infinite = 0xcfcfcfcf;
int prior(char x){ if (x=='*'||x=='/')return -1; else return -2; }
int type_element(char x) { if((x>='0' && x<='9')||(x>='a'&&x<='z')||(x>='A'&&x<='Z')) { return 1; } else if(x=='('||x=='{'||x=='[') { return 2; } else if(x==')'||x=='}'||x==']'){ return 3; } else return prior(x); }
bool pairElement(char x,char y){ if((x=='('&&y==')')||(x=='{'&&y=='}')||(x=='['&&y==']'))return true; else return false; }
void verdict(string str) { stack<char> S; int lens = str.length(); up(lens) { int t = type_element(str[i]); if(t==1)printf("%c ",str[i]); else if(t==2)S.push(str[i]); else if(t==3){ while(!S.empty()){ char tmp=S.top(); S.pop(); if(type_element(tmp)!=2)printf("%c ",tmp); if(pairElement(tmp,str[i]))break; } } else { while(!S.empty()){ char tmp=S.top(); if(type_element(tmp)==2)break; if(prior(tmp)>=t){ S.pop(); printf("%c ",tmp); } else break; } S.push(str[i]); } } while(!S.empty())printf("%c ",S.top()),S.pop();
}
int main() { string str; cin>>str; verdict(str); return 0; }
|
参考
🔗数据结构——中缀转后缀表达式🔗
🔗中缀表示法-Wikipedia🔗