字尾表示式學習筆記
中綴表示式:
類似於這樣的表示式:a +b * c - ( d * c + e ) / f,就是人類算的表示式,叫做中綴表示式,中綴表示式我們雖然可以輕易地得出運算順序,但是計算機卻不行,需要計算機程式化地處理一個表示式並運算,通常要轉化成字尾表示式的形式。
字尾表示式:
上述表示式化為字尾表示式為:a b c * + d c * e + f / -,其運算過程為不斷將表示式中的數字壓入棧中,如果遇到運算子,則直接將運算子作用於棧最上面的兩個元素。 就好像下面這個例子: 8 - ( 3 + 2 * 6 ) / 5 + 4 轉化成字尾表示式: 8 3 2 6 * + 5 / - 4 + 8 3 12 + 5 / - 4 + 8 15 5 / - 4 + 8 3 - 4 + 5 4 + 9 這樣程式化地計算,則可以線上性時間內得到運算結果。
中綴如何轉化成字尾:
由於字尾表示式是按照順序依次壓入棧中並且計算的,所以在轉化的時候就應該要考慮各種運算子的運算順序問題。
這裡的處理直接按照順序讀取中綴表示式的每一個部分。
如果中途得到的運算子運算優先順序是遞增的,那麼則不可以立馬錶示到字尾表示式中,而是要等出現一個運算優先順序較底的運算子才可以,這個過程也用棧來處理。
a +b * c,好比這個例子,在+運算子讀到的時候+並不是直接作用於a b的,因為後面還有一個優先順序較高的運算子*。
於是我們便大體上得到了這樣一個流程:
1.數字直接放入字尾表示式中。
2.如果遇到非括號的運算子,則在放入棧中之前先不斷地將優先順序級>=此運算子的運算子從棧中彈出並放入字尾表示式。
3.遇到左括號,直接放入棧中,不需要彈出任何運算子,因為這括號裡面的肯定是要最先算的。
4.遇到右括號,表示這個括號裡面的東西算完了,相當於結束了一個子算式,直接從棧中彈運算子直到遇到左括號為止。
按照上面的步驟進行,中綴就可以轉成字尾了。
例題:
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
typedef long long ll;
using namespace std;
void File(){
freopen("luogu1175.in","r",stdin);
freopen("luogu1175.out","w",stdout);
}
const int maxn=1000+10;
int len,tot;
char s[maxn];
stack<char >stk;
int wei(char ch){
if(ch=='+' || ch=='-')return 1;
if(ch=='*' || ch=='/')return 2;
if(ch=='^')return 3;
return 0;
}
struct node{bool ty;int num;char ch;}qu[maxn];
void popchar(){
qu[++tot]=(node){1,0,stk.top()};
stk.pop();
}
void output(int p){
if(qu[p].ty==0)printf("%d ",qu[p].num);
else printf("%c ",qu[p].ch);
}
//+ - * / ^ ( will only in the stack
void init(){
scanf("%s",s+1);
len=strlen(s+1);
REP(i,1,len){
if(isdigit(s[i])){
qu[++tot]=(node){0,s[i]-'0','\0'};
continue;
}
if(s[i]=='(')stk.push(s[i]);
else if(s[i]==')'){
while(stk.top()!='(')popchar();
stk.pop();
}
else{
while(!stk.empty() && wei(stk.top())>=wei(s[i]))popchar();
stk.push(s[i]);
}
}
while(!stk.empty())popchar();
//REP(i,1,tot)output(i);
}
void work(){
REP(i,1,tot)output(i);
while(tot>1){
putchar('\n');
int p=1;
while(!qu[p].ty)++p;
if(qu[p].ch=='+')qu[p-2].num=qu[p-2].num+qu[p-1].num;
if(qu[p].ch=='-')qu[p-2].num=qu[p-2].num-qu[p-1].num;
if(qu[p].ch=='*')qu[p-2].num=qu[p-2].num*qu[p-1].num;
if(qu[p].ch=='/')qu[p-2].num=qu[p-2].num/qu[p-1].num;
if(qu[p].ch=='^')qu[p-2].num=pow(qu[p-2].num,qu[p-1].num);
REP(i,p-1,tot-2)swap(qu[i],qu[i+2]);
tot-=2;
REP(i,1,tot)output(i);
}
}
int main(){
// File();
init();
work();
return 0;
}