鏈接:https://www.zhihu.com/question/41103160/answer/452481026
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
Wikipedia 已經說得很清楚了,我只是復述一下。
逆波蘭表達式,英文為 Reverse Polish notation,跟波蘭表達式(Polish notation)相對應。之所以叫波蘭表達式和逆波蘭表達式,是為了紀念波蘭的數理科學家 Jan Łukasiewicz。其在著作中提到:
我在1924年突然有了一個無需括號的表達方法,我在文章第一次使用了這種表示法。
- 平時我們習慣將表達式寫成 (1 + 2) * (3 + 4),加減乘除等運算符寫在中間,因此稱呼為中綴表達式。
- 而波蘭表達式的寫法為 (* (+ 1 2) (+ 3 4)),將運算符寫在前面,因而也稱為前綴表達式。
- 逆波蘭表達式的寫法為 ((1 2 +) (3 4 +) *),將運算符寫在后面,因而也稱為后綴表達式。
波蘭表達式和逆波蘭表達式有個好處,就算將圓括號去掉也沒有歧義。上述的波蘭表達式去掉圓括號,變為 * + 1 2 + 3 4
。逆波蘭表達式去掉圓括號,變成 1 2 + 3 4 + *
也是無歧義並可以計算的。事實上我們通常說的波蘭表達式和逆波蘭表達式就是去掉圓括號的。而中綴表達式,假如去掉圓括號,將 (1 + 2) * (3 + 4) 寫成 1 + 2 * 3 + 4,就改變原來意思了。
現實中,波蘭表達式和逆波蘭表達式,具體用於什么地方呢?
波蘭表達式(前綴表達式),實際是抽象語法樹的表示方式,比如中綴 (1 + 2) * (3 + 4) 編譯時轉成的抽象語法樹為
*
/ \
+ +
/ \ / \
1 2 3 4
這個操作符就是根節點,操作數為左右子節點。我們將這棵樹用符號表達出來,可以寫成 (* (+ 1 2) (+ 3 4))。這實際就是 Lisp 的 S-表達式。S-表達式可看成將整棵抽象語法樹都寫出來,每層節點都加上圓括號。
至於逆波蘭表示式,可用棧進行計算,天生適合於基於棧的語言。遇到數字就將數字壓棧,遇到操作符,就將棧頂的兩個元素取出計算,將計算結果再壓入棧。比較典型的基於棧的語言為 Forth 和 PostScript。
延伸擴展一下。
我最近看了這篇文章,提高 lua 處理向量運算性能的一點嘗試,原文為了減少 lua 和 C 通信的交互成本,設計了一些向量運算的指令。將 mat1、mat2 壓棧,寫成
command ( mat1, mat2, "*~")
來替代中綴寫法
~ (mat1 * mat2)
command ( mat1, mat2, "*~")
實際就是逆波蘭表達式 mat1 mat2 * ~
。
再之后讀了這個文章 編程珠璣番外篇-P PostScript 語言里的珠璣。