- 表達式簡介
最近看書的時候接觸到了后綴表達式,恰好看SICP中間也碰到了類似的問題,就花時間好好將這部分內容進行了整理。
前綴表達式(Prefix Notation)是指將運算符寫在前面操作數寫在后面的不包含括號的表達式,而且為了紀念其發明者波蘭數學家Jan Lukasiewicz所以前綴表達式也叫做“波蘭表達式”。比如- 1 + 2 3
后綴表達式(Postfix Notation)與之相反,是指運算符寫在操作數后面的不含括號的算術表達式,也叫做逆波蘭表達式。比如1 2 3 + -
中綴表達式(Infix Notation)就是常用的將操作符放在操作數中間的算術表達式。前綴表達式和后綴表達式相對於中綴表達式最大的不同就是去掉了表示運算優先級的括號,比如1-2+3
現在讓我們先回想一下小學數學中關於中綴表達式求值的相關的規則:
1 有括號的情況下,先計算括號內,再計算括號外
2 在無括號的情況下,考慮運算的優先級,先乘除,后加減
3 同樣優先級的情況下,從左至右進行計算
在中綴表達式的情況下求值,既要考慮括號,優先級,還要考慮操作出現的先后順序。但是,作為計算機,其計算過程就顯的比較復雜,對於一個中綴表達式,需要不停地對表達式進行多次遍歷,來查找相應的計算的信息。這樣從算法復雜度上來說,是不可取的。
前綴表達式和后綴表達式相對於人們常用的中綴表達式最大的不同就在於表達式中的運算符是按照一定的順序出現(接下來會具體講解),所以求值過程中並不需要在表達式中使用括號來指定運算順序,也不需要在計算過程中其中考慮運算符號的優先級。在采用輔助數據結構的情況下,只需要對表達式進行一次遍歷即可計算出結果,大大降低了算法復雜度,也更加符合傳統計算機的工作方式。
- 表達式的轉換
在對前綴中綴和后綴表達式進行了簡單的介紹以后,接下來對表達式之間的轉換進行一個簡單的闡述,在這里首先以中綴表達式轉換后綴表達式為例進行較詳細的講解。
首先介紹一個人工轉換的方法,假設有一個中綴表達式a+b*c-(d+e)
1首先將這個中綴表達式的所有運算加括號((a+(b*c))-(d+e))
2然后將所有運算符放到括號后面,這樣就變成了((a(bc)* )+ (de)+ )-
3把所有括號去掉abc*+de+-,最后得出的結果就是后綴表達式
上面這個方法可以在比如做題分析的時候用人腦的時候使用,接下來介紹用程序實現將中綴轉換成后綴表達式的思路
1 建立一個棧,然后從左至右的遍歷中綴表達式
2 如果碰到了操作數,則直接將其輸出,如果碰到了操作符,這個時候則需要進行優先級的比較,如果棧為空或者棧頂的操作符的優先級比當前的低,則將當前的操作符Push入棧,如果棧頂操作符比當前的操作符的優先級高或者相同,則POP操作符並輸出,直到出現前一種情況為止
3 需要注意的是對於括號需要另外注意一下,如果是’(’,則直接入棧,如果是)則要找到對應的’(’為止,並且當兩者同時出現時則同時刪除
下面模擬程序對a+b*c-(d+e)求中綴表達式,首先對其進行掃描
輸出 a 棧底 棧頂
輸出 a 棧底 + 棧頂
輸出 a b 棧底 + 棧頂
輸出 a b 棧底 + * 棧頂
輸出 a b c 棧底 + * 棧頂
輸出 a b c * 棧底 + 棧頂
輸出 a b c * + 棧底 - 棧頂
輸出 a b c * + 棧底 - ( 棧頂
輸出 a b c * + d 棧底 - ( 棧頂
輸出 a b c * + d 棧底 - ( + 棧頂
輸出 a b c * + d e 棧底 - ( + 棧頂
輸出 a b c * + d e + 棧底 ( 棧頂
輸出 a b c * + d e + - 棧底 棧頂
上面已經把中綴表達式轉換后綴表達式的過程講解了一下,而中綴表達式轉換前綴表達式其實過程和轉換后綴表達式及其相似,在這里就不說具體過程了,只是對其中的幾個不同之處稍微說明一下:
1 轉換后綴表達式由於符號是要在操作數后面出現,所以操作數入棧,掃描順序是從左向右,轉換前綴表達式的話操作符需要在操作數前面出現,那么掃描順序就應該是從右向左。
2 操作符的具體處理方式和轉換到后綴表達式略有不同
3 括號的操作也是’)’直接入棧,’(’則配對’)’后一起出棧
- 前綴,中綴,后綴表達式與二叉樹的表示
這三個表達式其實與二叉樹是有這很緊密的聯系的,a+b*c-(d+e)這個中綴表達式我們將其操作符當做內節點,操作數當做葉子節點,這樣的話就能夠畫出這個中綴表達式所對應的二叉樹
如果我們對這個中綴表達式進行前序和后序遍歷,則輸出的結果就是其對應的前綴和后綴表達式。
本篇Blog我所參考的資料