中綴表達式,後綴表達式以及它們的轉換

先說一說中綴表達式。

中綴表達式也就是我們常用常說的算術表達式,像5*3,   3+4*6,  (4+2)/6,(4-1)*(21+4) 這些都是中綴表達式。中綴表達式的特點是運算符在被運算的兩個數中間。

 中綴表達式的運算對我們來說並不難,簡單的中綴表達式我們小學就會了。但對於電腦來說,運算中綴表達式卻並不簡單。電腦不懂加減乘除的優先級,如果再加幾個括號套過去套過來,只會把電腦搞的不要不要的~

這時候,我們就需要一種優秀的方法來解決這個問題了。於是就有了後綴表達式。

顧名思義,後綴表達式就是運算符在被運算的兩個數後面。像5*3寫成後綴表達式就是53*,4*2+3就是42*3+。後綴表達式沒有括號,運算符也沒有優先級,所有運算都是從左往右的。

後綴表達式的運算較爲簡單,從左往右依次讀取,如果讀到運算符,就把運算符前兩個數字執行相應運算,將結果保存到這個位置。比如4 2 * 3 +,先從左往右讀取,第三個遇到*,就把*前面的4和2拿出來相乘,得到8,把8放回去,後綴表達式就變成了8 3 +,再次讀取到+,8加上3等於11,就得到了4 2 * 3 +這個後綴表達式的值爲11.

後綴表達式沒有優先級,括號優先級這些都體現在它的存放順序中,它存放的順序直接決定了運算的順序。中綴表達式3+4*6可以表示成3 4 6 * +,也可以更直觀地表示成4 6 * 3 +。像中綴表達式(4+2)/6表示成後綴表達式就是4 2 + 6 /

電腦運算後綴表達式就很方便了,只需要從左往右跑一遍就可以了,而不需要像我們運算中綴表達式那樣跳過去跳過來的。如果我們要用電腦處理中綴表達式,可以先將中綴表達式轉化爲後綴表達式。


接下來就是重點難點了,中綴轉後綴。

中綴轉後綴要用到棧。

1.先寫簡單的中綴轉後綴,一位數的不包含括號的中綴表達式轉換:

將中綴表達式先保存到一個字符串a,再創一個字符串b用於儲存產生的後綴表達式,同時還需要一個用於存運算符的棧c。

這裏的運算符有個優先級的概念,有必要先說一下。每個運算符的優先級不同,我簡單歸納了一下:


+ - * / ( )
2 2 3 3 1 4 0

這裏有個#號不是運算符,後面用的時候再說。

初始b和棧c都爲空,a裏面有一箇中綴表達式。然後從左往右依次讀取中綴表達式a的每一位,a[i]如果是數字就直接存進字符串b這裏的數字都是一位數),如果是運算符就和棧頂元素比較,如果這個運算符的優先級大於或等於棧頂運算符的優先級,就把棧頂運算符取出來放進b字符串裏面,然後再用該運算符a[i]繼續和棧頂運算符進行比較,重複上面的操作,一直到找到優先級低於它的運算符或者棧爲空。從左往右一直把a字符串跑完一遍後,b裏面已經有一部分後綴表達式了,棧c裏面可能還有一部分運算符。那麼,我們接下來只需要把棧c裏面的運算符倒進b裏面就行了,也就是把棧c的元素依次出棧並存到字符串b裏面。這樣一個後綴表達式b就完成了。

這裏有個小技巧,可以在開始前先朝棧c裏面放一個字符#,字符#的優先級是最低的,沒有運算符能把它彈出來。這樣判斷的時候就不用判斷是否爲空棧了。

 實戰轉換一下3*6+3。注意這裏的數字都是以字符的形式存的,所以運算的時候要減去個0字符。

首先創字符串a,b和棧c:

字符串a a[i](操作的字符) 操作 字符串b 棧c
3*6+3
3 3進b 3 NULL
3*6+3
* *進c 3 *
3*6+3
6 6進b 3 6 *
3*6+3
+ *的優先級大於+,彈出*到b,c爲空,+進c 3 6 * +
3*6+3
3 3進b 3 6 * 3  +

a中處理完了 將c中元素倒入b 3 6 * 3 + NULL
 

得到了它的後綴表達式爲3 6 * 3 +

這是最簡單的一種中綴轉後綴了,基礎理解好了後面就好說了。

2.然後就是有括號的中綴表達式,例如6*(4+2)/2

依然是從左往右讀,其他處理方式也一樣,只是兩個括號處理方式不同。讀到左括號(不用判斷直接存進棧c,不把其他運算符彈出棧。如果讀到右括號) 不用進棧,直接一個個把棧c的運算符出棧到b裏面,直到遇到到左括號( ,然後把左括號出棧扔了。繼續往後讀a[i]。

6*(4+2)/2算一遍:

字符串a a[i](操作的字符) 操作   字符串b   棧c
6*(4+2)/2
6 6進b 6 NULL
6*(4+2)/2
* *進c 6 *
6*(4+2)/2
( (直接進c 6 *(
6*(4+2)/2
4 4進b 6 4 *(
6*(4+2)/2 + +進c 6 4 *(+
6*(4+2)/2 2 2進b 6 4 2 *(+
6*(4+2)/2 ) 取棧c的棧頂+,+進b,再取棧頂(,直接刪除 6 4 2 + *
6*(4+2)/2 / *的優先級等於/,*進b,c棧空,/進c 6 4 2 + /
6*(4+2)/2 2 2進b 6 4 2 + * 2 */
  a處理完畢 c倒入b中 6 4 2 + * 2 / NULL






所以,6*(4+2)/2的後綴表達式爲6 4 2 + * 2 /

3.然後再說多位數的。比如32+45*12這種。

關鍵是題目中的數字是以字符的形式儲存的,並不是他們真正的值。

這裏有兩種方法解決,一種是讀取的時候如果爲連續數字,則直接乘十往後加,也就是加出它真實的數字。比如32,先讀取3,然後讀取2,因爲是連續數字,所以3*10+2=32。這種方法比較方便,但應用實在有限,因爲是字符類型保存的,所以保存的值的大小不能超過256。並且這個數字還可能和運算符的ascll碼相同,導致最後當成了運算符處理。所以這方法其實沒什麼卵用~

第二種是普遍方法,更利於中綴轉後綴後輸出。簡單說就是在後綴表達式的每個數字完了後加上一個#,這樣會讓b字符串變成類似這樣的樣子:3 2 # 4 5 # 1 2 # * /  。這樣輸出的時候還需要稍作處理再輸出。

還是以32+45*12爲例寫一下吧:

字符串a a[i](操作的字符) 操作 字符串b 棧c
32+45*12
3 3進b 3 NULL
32+45*12 2 2進b 3 2 NULL
32+45*12 + +不爲數字,#進b,+進c 3 2 # +
32+45*12 4 4進b 3 2 # 4 +
32+45*12 5 5進b 3 2 # 4 5 +
32+45*12 * *不爲數字,#進b,*進c 3 2 # 4 5 # +*
32+45*12 1 1進b 3 2 # 4 5 # 1 +*
32+45*12 2 2進b 3 2 # 4 5 # 1 2 +*

a處理完了 最後一個爲數字,#進b,c倒入b  3 2 # 4 5 # 1 2 # * +  NULL


寫了幾個小時,終於寫完了~~

累~

字符串a a[i](操作的字符) 操作 字符串b 棧c
6*(4+2)/2
6 6進b 6 NULL
6*(4+2)/2
* *進c 6 *
6*(4+2)/2
( (直接進c 6 *(
6*(4+2)/2
4 4進b 6 4 *(
6*(4+2)/2
+ +進c 6 4 *(+
6*(4+2)/2
2 2進b 6 4 2 *(+
6*(4+2)/2
) 取棧c的棧頂元素+,+進b,再取棧頂元素( ,直接刪除
6 4 2 + *
字符串a a[i](操作的字符) 操作 字符串b 棧c
6*(4+2)/2
6 6進b 6 NULL
6*(4+2)/2
* *進c 6 *
6*(4+2)/2
( (直接進c 6 *(
6*(4+2)/2
4 4進b 6 4 *(
6*(4+2)/2
+ +進c 6 4 *(+
6*(4+2)/2
2 2進b 6 4 2 *(+
6*(4+2)/2
) 取棧c的棧頂元素+,+進b,再取棧頂元素( ,直接刪除
6 4 2 + *
字符串a a[i](操作的字符) 操作 字符串b 棧c
6*(4+2)/2
6 6進b 6 NULL
6*(4+2)/2
* *進c 6 *
6*(4+2)/2
( (直接進c 6 *(
6*(4+2)/2
4 4進b 6 4 *(
6*(4+2)/2
+ +進c 6 4 *(+
6*(4+2)/2
2 2進b 6 4 2 *(+
6*(4+2)/2
) 取棧c的棧頂元素+,+進b,再取棧頂元素( ,直接刪除
6 4 2 + *
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章