【詳細筆記】前綴、中綴以及后綴表達式 (JS Version)

前言

最近開始刷題,真實地解決了大學時期“這黑窗口敲來敲去做數學題有卵用?”的困惑。有些東西之前學過,現在忘了,但是正是因為學過,所以再學一遍就變得效率很高(但是我還是不認可大學的學科教學順序)。廢話不多說,這篇博客只是一個筆記,希望之后有了更深的認識能夠完善。

前綴、中綴以及后綴表達式是什么?

先聚合一下定義,以后萬一要復習也好找XD

前綴表達式

波蘭表示法(Polish notation,或波蘭記法),是一種邏輯、算術和代數表示方法,其特點是操作符置于操作數的前面,因此也稱做前綴表示法

中綴表達式

中綴表示法(或中綴記法)是一個通用的算術或邏輯公式表示方法, 操作符是以中綴形式處于操作數的中間(例:3 + 4)。與前綴表達式(例:+ 3 4)或后綴表達式(例:3 4 +)相比,中綴表達式不容易被電腦解析,但仍被許多程序語言使用,因為它符合人們的普遍用法。

與前綴或后綴記法不同的是,中綴記法中括號是必需的。計算過程中必須用括號將操作符和對應的操作數括起來,用于指示運算的次序。

后綴表達式

逆波蘭表示法(Reverse Polish notation,RPN,或逆波蘭記法),是一種是由波蘭數學家揚·武卡謝維奇1920年引入的數學表達式方式,在逆波蘭記法中,所有操作符置于操作數的后面,因此也被稱為后綴表示法。逆波蘭記法不需要括號來標識操作符的優先級。

對中綴表達式進行轉換

這應該是基礎中的基礎了,理解并記憶思路,再跟著栗子走兩步,最后敲一遍代碼,基本就掌握了。

中綴表達式轉前綴表達式

思路

  1. 初始化兩個棧:運算符棧 S1; 操作數棧 S2
  2. 從右至左掃描中綴表達式
  3. 遇到操作數時,將其壓入 S2
  4. 遇到運算符時,比較其與 S1 棧頂運算符的優先級
    1. 如果<span style="font-weight:bold"> S1 為空</span>,或棧頂運算符為右括號 ")",或其優先級比棧頂運算符的優先級較高或相等,則直接將此運算符入棧
    2. 否則,將 S1 棧頂的運算符彈出并壓入到 S2 中,再次進行與 S1 棧頂運算符的優先級比較
  5. 遇到括號
    1. 如果是右括號 ")",則直接壓入 S1
    2. 如果是左括號 "(",則依次彈出 S1 棧頂的運算符,并壓入 S2,直到遇到右括號 ")" 為止,此時將這一對括號丟棄
  6. 重復步驟 2 至 5,直到表達式的最左邊
  7. S1 剩余的運算符依次彈出并壓入 S2
  8. 依次彈出 S2 中的元素并輸出,結果即為中綴表達式對應的前綴表達式

栗子

(1 + (3 * 4) / 6 ) - 5

掃描到的元素 S2 (棧底 -> 棧頂) S1 (棧底 -> 棧頂) 說明
5 5 操作數,直接入棧 S2
- 5 - 運算符S1 為空,直接入棧
) 5 - ) 右括號,直接入棧 S1
6 5 6 - ) 操作數,直接入棧 S2
/ 5 6 - ) / 運算符,且 S1 棧頂為 右括號,直接入棧
) 5 6 - ) / ) 右括號,直接入棧 S1
4 5 6 4 - ) / ) 操作數,直接入棧 S2
* 5 6 4 - ) / ) * 運算符,且 S1 棧頂為 右括號,直接入棧
3 5 6 4 3 - ) / ) * 操作數,直接入棧 S2
( 5 6 4 3 * - ) / 左括號S1 棧彈出運算符壓入 S2 直至遇到右括號,一對括號丟棄
+ 5 6 4 3 * / - ) + 運算符,但優先級低于 S1 棧頂運算符,S1 彈出運算符壓入 S2,直至棧頂優先級低于運算符,再入棧
1 5 6 4 3 * / 1 - ) + 操作數,直接入棧 S2
( 5 6 4 3 * / 1 + - 左括號S1 棧彈出運算符壓入 S2 直至遇到右括號,一對括號丟棄
到達最左端 5 6 4 3 * / 1 + - S1 剩余的運算符依次彈出并壓入 S2

依次彈出 S2 中的元素并輸出結果: -+1/*3465

代碼

carbon_1577593826257.png

中綴表達式轉后綴表達式

思路

  1. 初始化兩個棧:運算符棧 S1; 操作數棧 S2
  2. 從左至右掃描中綴表達式
  3. 遇到操作數時,將其壓入 S2
  4. 遇到運算符時,比較其與 S1 棧頂運算符的優先級
    1. 如果<span style="font-weight:bold"> S1 為空</span>,或棧頂運算符為左括號 "(",或其優先級比棧頂運算符的優先級較高,則直接將此運算符入棧
    2. 否則,將 S1 棧頂的運算符彈出并壓入到 S2 中,再次進行與 S1 棧頂運算符的優先級比較
  5. 遇到括號時
    1. 如果是左括號 "(",則直接壓入 S1
    2. 如果是右括號 ")",則依次彈出 S1 棧頂的運算符,并壓入 S2,直到遇到左括號 "(" 為止,此時將這一對括號丟棄
  6. 重復步驟 2 至 5,直到表達式的最右邊
  7. S1 剩余的運算符依次彈出并壓入 S2
  8. 拼接 S2 中的元素并輸出,結果即為中綴表達式對應的后綴表達式

栗子

(1 + (3 * 4) / 6 ) - 5

掃描到的元素 S2 (棧底 -> 棧頂) S1 (棧底 -> 棧頂) 說明
( ( 左括號,直接入棧 S1
1 1 ( 操作數,直接入棧 S2
+ 1 ( + 運算符,且 S1 棧頂為 左括號,直接入棧
( 1 ( + ( 左括號,直接入棧 S1
3 1 3 ( + ( 操作數,直接入棧 S2
* 1 3 ( + ( * 運算符,且 S1 棧頂為 左括號,直接入棧
4 1 3 4 ( + ( * 操作數,直接入棧 S2
) 1 3 4 * ( + 右括號,S1 棧彈出運算符壓入 S2 直至遇到左括號,一對括號丟棄
/ 1 3 4 * ( + / 運算符,且優先級高于 S1 棧頂的運算符,直接入棧
6 1 3 4 * 6 ( + / 操作數,直接入棧 S2
) 1 3 4 * 6 / + 右括號,S1 棧彈出運算符壓入 S2 直至遇到左括號,一對括號丟棄
- 1 3 4 * 6 / + - 運算符,S1 為空,直接入棧
5 1 3 4 * 6 / + 5 - 操作數,直接入棧 S2
到達最右端 1 3 4 * 6 / + 5 - S1 剩余的運算符依次彈出并壓入 S2

拼接 S2 中的元素并輸出結果:134*6/+5-

代碼

carbon.png

考題擴展

leetcode 150. 逆波蘭表達式求值

根據逆波蘭表示法,求表達式的值。
有效的運算符包括 +, -, *, / 。每個運算對象可以是整數,也可以是另一個逆波蘭表達式。
說明:
整數除法只保留整數部分。
給定逆波蘭表達式總是有效的。換句話說,表達式總會得出有效數值且不存在除數為 0 的情況。

對比上面的操作,這題考的是一個逆向思維。

思路

  1. 初始化一個棧 stack 和一個包含 +-*/ 操作的操作策略對象 operation
  2. 從左至右掃描逆波蘭表達式
    1. 遇到操作數時,壓入棧 stack
    2. 遇到運算符時,依次取出棧頂的兩個元素b、a(為了照顧(減)除法操作,先出棧的為被(減)除數 b ,后出棧的為(減)除數 a ),調用 operation 策略對象的相應方法,并將運算結果入棧 stack
  3. 重復步驟 2,直到表達式的最右邊
  4. 彈出棧頂元素即是運算結果

代碼

carbon的副本.png

波蘭表達式求值

這個就舉一反三就完事了。

思路

  1. 初始化一個棧 stack 和一個包含 +-*/ 操作的操作策略對象 operation
  2. 從右至左掃描波蘭表達式
    1. 遇到操作數時,壓入棧 stack
    2. 遇到運算符時,依次取出棧頂的兩個元素a、b(為了照顧(減)除法操作,先出棧的為被(減)除數 a ,后出棧的為(減)除數 b ),調用 operation 策略對象的相應方法,并將運算結果入棧 stack
  3. 重復步驟 2,直到表達式的最左邊
  4. 彈出棧頂元素即是運算結果

代碼

carbon的副本2.png

模擬 eval('(1 + (3 * 4) / 6 ) - 5')

思路

經過上面的熟悉和理解,這個就很簡單了,只要將中綴表達式轉換成后綴表達式或者前綴表達式其中的一種,再進行求值即可,代碼就是把上面的組裝一下,這里就不列出了。

后記

工作一段時間,算法和數據結構漸漸生疏了,在刷題的時候,又把大學的學習的知識慢慢找回來,雖然要花一段時間,但是一旦將時間投入進去,會慢慢地感興趣,進入良性循環。

貼個GitHub,剛剛起步進行“圣地巡禮”:https://github.com/LazyDuke/leetcode-js

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,606評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,582評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,540評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,028評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,801評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,223評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,294評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,442評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,976評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,800評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,996評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,543評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,233評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,926評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,702評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,991評論 2 374

推薦閱讀更多精彩內容

  • 中綴 人類正常使用的計算表達式即為中綴表達式比如:( 1 + 2 ) * 3 - 4 前綴 前綴表達式的計算邏輯為...
    spraysss閱讀 840評論 0 1
  • 參考:前綴、中綴、后綴表達式(逆波蘭表達式) - chensongxian - 博客園 中綴表達式就是人們日常生活...
    單袍豬皮閱讀 624評論 0 0
  • 百度百科 ??逆波蘭表達式又叫做后綴表達式。在通常的表達式中,二元運算符總是置于與之相關的兩個運算對象之間,這種表...
    Taoyongpan閱讀 908評論 0 7
  • 概念 前綴表達式(波蘭表達式)運算符位于操作數前,右到左依次入棧 中綴表達式從左到右依次入棧,一般轉為后綴表達式 ...
    RalapHao閱讀 543評論 0 0
  • 1.今天在港鐵上讀羊皮卷,當陽光照耀車廂,散落在手中書上,字里行間暖陽點點,突然覺得應該感謝港鐵,它是我每天往返深...
    朗朗晴空1閱讀 116評論 0 0