1. 程式人生 > >字尾表示式學習筆記

字尾表示式學習筆記

中綴表示式:

類似於這樣的表示式: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; }