前/中/後綴的那些事兒
自然表達式轉換爲前/中/後綴表達式。首先將自然表達式按照優先級順序,構造出與表達式相對應的二叉樹,然後對二叉樹進行前/中/後綴遍歷,即得到前/中/後綴表達式。
由樹的遍歷——
① 前序遍歷:根-左-右
② 中序遍歷:左-根-右
③ 後序遍歷:左-右-根
可以得出:
前綴表達式:前序遍歷
中綴表達式:中序遍歷
後綴表達式:後序遍歷
中綴表達式按操作符的優先級進行計算(後面代碼實現只包括+、-、*、\,小括號),即數學運算。 後綴表達式中只有操作數和操作符。操作符在兩個操作數之後。它的計算規則非常簡單,嚴格按照從左到右的次序依次執行每一個操作。每遇到一個操作符,就將前面的兩個數執行相應的操作。
由後綴表達式計算中綴表達式原理:計算機處理後綴表達式求值問題是比較方便的,即將遇到的操作數暫存於一個操作數棧中,凡是遇到操作數,便從棧中pop出兩個操作數,並將結果存於操作數棧中,直到對後綴表達式中最後一個操作數處理完,最後壓入棧中的數就是後最表達式的計算結果。
中綴表達式轉換爲等價的後綴表達式 :
我們把平時所用的標準四則將中綴表達式轉化爲後綴表達式運算表達式,即“9+(3-1)*3+10/2"叫做中綴表達式。因爲所有的運算符號都在兩數字的中間,現在我們的問題就是中綴到後綴的轉化。
中綴表達式“9+(3-1)*3+10/2”轉化爲後綴表達式“9 3 1-3*+ 10 2/+”
規則:從左到右遍歷中綴表達式的每個數字和符號,若是數字就輸出,即成爲後綴表達式的一部分;若是符號,則判斷其與棧頂符號的優先級,是右括號或優先級低於棧頂符號(乘除優先加減)則棧頂元素依次出棧並輸出,並將當前符號進棧,一直到最終輸出後綴表達式爲止。
算法描述:
將中綴表達式轉換爲等價的後綴表達式的過程要使用一個棧放“(”,具體可以按照下面的方式進行。
(1)從左到右依次掃描中綴表達式的每一個字符,如果是數字字符和圓點“.”則直接將它們寫入後綴表達式中。
(2)如果遇到的是開括號“(”,則將它們壓入一個操作符棧(不需要與棧頂操作符相比較),它表明一個新的計算層次的開始,在遇到和它匹配的閉括號“)”時,將棧中的元素彈出來並放入後綴表達式中,直到棧頂元素爲“(”時,將棧頂元素“(”彈出(不需要加入後綴表達式),表明這一層括號內的操作處理完畢。
(3)如果遇到的是操作符,則將該操作符和操作符棧頂元素比較:
1、當所遇到的操作符的優先級小於或等於棧頂元素的優先級時,則取 出棧頂元素放入後綴表達式,並彈出該棧頂元素,反覆執行直到當前操作符的優先級大於棧頂元素的優先級;
2、當所遇到的操作符的優先級大於棧頂元素的優先級的時則將它壓入棧中。 即可以概括爲膽小的怕膽大的,膽大的怕不要命的——” ) ”.
下面我們來具體看看這個過程。
1. 初始化一空棧,用來對符號進出棧使用。
2. 第一個字符是數字9,輸出9,後面是符號“+”,進棧。
3. 第三個字符是“(”,依然是符號,因其只是左括號,還未配對,故進棧。
4. 第四個字符是數字3,輸出,總表達式爲9 3,接着是“-”進棧。
5. 接下來是數字1,輸出,總表達式爲9 3 1,後面是符號“)”,此時,我們需要去匹配此前的“(”,所以棧頂依次出棧,並輸出,直到“(”出棧爲止。此時左括號上方只有“-”,因此輸出“-”,總的輸出表達式爲9 3 1 -
6. 接着是數字3,輸出,總的表達式爲9 3 1 - 3 。緊接着是符號“*”,因爲此時的棧頂符號爲“+”號,優先級低於“*”,因此不輸出,進棧。
7. 之後是符號“+”,此時當前棧頂元素比這個“+”的優先級高,因此棧中元素出棧並輸出(沒有比“+”號更低的優先級,所以全部出棧),總輸出表達式爲 9 3 1 - 3 * +.然後將當前這個符號“+”進棧。也就是說,前6張圖的棧底的“+”是指中綴表達式中開頭的9後面那個“+”,而下圖中的棧底(也是棧頂)的“+”是指“9+(3-1)*3+”中的最後一個“+”。
8. 緊接着數字10,輸出,總表達式變爲9 3 1-3 * + 10。
9. 最後一個數字2,輸出,總的表達式爲 9 3 1-3*+ 10 2
10. 因已經到最後,所以將棧中符號全部出棧並輸出。最終輸出的後綴表達式結果爲 9 3 1-3*+ 10 2/+
·
從剛纔的推導中你會發現,要想讓計算機具有處理我們通常的標準(中綴)表達式的能力,最重要的就是兩步:
·
1. 將中綴表達式轉化爲後綴表達式(棧用來進出運算的符號)。
2. 將後綴表達式進行運算得出結果(棧用來進出運算的數字)。
整個過程,都充分利用了找的後進先出特性來處理,理解好它其實也就理解好了棧這個數據結構。
+++++++++++++++++++++++++++++++++++++++主要代碼如下++++++++++++++++++++++++++++++++++++++++++++
1.中綴轉後綴
int pre(char a) //操作符優先級比較
{
if(a == '=' || a == '(')
return 0;
else if(a == '+' || a == '-')
return 1;
else if(a == '*' )
return 2;
else if(a=='^')
return 3;
}
void change(string str)
{
int 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();
}
}
2.後綴表達式的計算
long long strnum(string s)
{
long long num;
stringstream ss(s);
ss>>num;
return num;
}
long long work(string s)//後綴表達式的計算
{
string ss;
ss="";
memset(sta,0,sizeof(sta));top=0;
for(int i=0;i<s.size();i++)
{
if(s[i]>='0'&&s[i]<='9')
ss+=s[i];
else
{
if(s[i]==' ')
{
top++;
sta[top]=strnum(ss);
ss="";
}
else
{
if(s[i]=='-')
{
int s1,s2;
s2=sta[top];
if(top>0)
{top--;
s1=sta[top];
s1-=s2;
sta[top]=s1;}
continue;
}
if(s[i]=='+')
{
int s1,s2;
s2=sta[top];
if(top>0)
{top--;
s1=sta[top];
s1+=s2;
sta[top]=s1;}
continue;
}
if(s[i]=='*')
{
int s1,s2;
s1=sta[top];if(top>0) top--;
s2=sta[top];
s1*=s2;
sta[top]=s1;
continue;
}
if(s[i]=='^')
{
int s1,s2;
s1=sta[top];if(top>0) top--;
s2=sta[top];
int z=1;
for(int i=1;i<=s1;i++)
z*=s2;
sta[top]=z;
continue;
}
}
}
}if(top==0)return strnum(ss);
else return sta[top];
}
本文參考一下博客內容:
——http://www.nowamagic.net/librarys/veda/detail/2307
——http://www.blogjava.net/wxqxs/archive/2009/05/21/277336.html
——http://blog.csdn.net/niushuai666/article/details/6702964
對以上作者表示衷心的感謝!
另:轉載請註明以上博客信息,及本博客信息