在本篇文章當中主要跟大家介紹以下幾點
表示式求值這是一個比較經典的計算機系統基礎問題,但是整個過程比較抽象,本文主要通過圖解的方法幫助大家理解這個問題。
字尾表示式也稱作逆波蘭表示式,字首表示式也稱作波蘭表示式,這個是因為這是由波蘭數學家楊-武卡謝維奇提出來的,用於簡化命題邏輯的一種方法。
我們常見的數學表示式就是中綴表示式,比如說:\(1 + 2\),像這種我們從小到大經常見到的表示式就叫做中綴表示式,這個表示式的特點就是將運運算元(加減乘除)放在兩個運算元(數位)中間。
字尾表示式和中綴表示式的最大區別就是,他不是將運運算元放在運算元中間,而是將運運算元放在運算元後面,比如上面的中綴表示式\(1 + 2\)轉化成字尾表示式就為\(12+\)。
字首表示式就是將運運算元放在運算元的前面,比如上面的中綴表示式\(1 + 2\)轉化成字首表示式之後為\(+12\)。
上面的表示式還是比較簡單,可能不足以幫助大家好好理解表示式之間的轉化過程。
中綴表示式:\(A + B * (C - D) - E / F\)
現在我們來將上面的中綴表示式轉化成字尾表示式,我們的第一個計算的部分如下(括號裡面的優先計算):
根據我們的轉化原理:將運運算元放在運算元後面,
上面的得到的字尾表示式繼續進行轉化(現在需要計算\(B\)乘以後面的那個部分):
繼續進行轉化(從左往後進行計算):
繼續進行轉化(除法的優先順序比減法高):
得到最終的結果:
將中綴表示式轉化成字尾表示式有以下幾條規則(下面的棧是儲存操作符的棧,而且只儲存操作符):
現在我們根據上面的規則來將上文當中的中綴表示式轉化成字尾表示式。
遍歷到\(C\),則直接將其加入到字尾表示式當中,當前字尾表示式為\(ABC\)。
遍歷到\(-\),根據規則將其加入到棧中,當前字尾表示式為\(ABC\)。
遍歷到\(D\),則將其直接加入到字尾表示式當中,當前的字尾表示式為\(ABCD\)。
遍歷到\()\),則需要將棧中的符號彈出,直到遇到\((\),當前的字尾表示式為\(ABCD-\)。
遍歷到\(E\),直接將數位加入到字尾表示式當中,則當前的字尾表示式為\(ABCD-*+E\)。
遍歷到\(/\),將棧中優先順序大於等於\(/\)的運運算元,再將\(/\)壓入到棧中,當前的字尾表示式為\(ABCD-*+E\)。
經過上面的過程就可以將一箇中綴表示式轉成字尾表示式了,大家如果想要程式碼實現,只需要在遍歷資料的時候根據上面四個規則一個個進行判斷即可,程式並不困難,就是邏輯稍微有點多,需要考慮更多的問題,在寫程式碼的時候需要細緻一點。
在前文當中我們已經得到了表示式\(A + B * (C - D) - E / F\)的字尾表示式為\(ABCD-*+EF/-\)。現在我們需要將這個字尾表示式進行求值。根據字尾表示式求值主要有以下兩條規則:
現在我們進行字尾表示式的求值過程;
相信經過上面過程你對字尾表示式求值的過程已經非常清楚了。
在LeetCode中有一道題就是根據字尾表示式求值——劍指 Offer II 036. 字尾表示式
根據 逆波蘭表示法,求該字尾表示式的計算結果。
有效的算符包括
+
、-
、*
、/
。每個運算物件可以是整數,也可以是另一個逆波蘭表示式。說明:
- 整數除法只保留整數部分。
- 給定逆波蘭表示式總是有效的。換句話說,表示式總會得出有效數值且不存在除數為 0 的情況。
範例 1:
輸入:tokens = ["2","1","+","3","*"]
輸出:9
解釋:該算式轉化為常見的中綴算術表示式為:((2 + 1) * 3) = 9範例 2:
輸入:tokens = ["4","13","5","/","+"]
輸出:6
解釋:該算式轉化為常見的中綴算術表示式為:(4 + (13 / 5)) = 6
上面問題的程式碼如下:
class Solution {
public int evalRPN(String[] tokens) {
Stack<Integer> stack = new Stack<>();
for (String token : tokens) {
switch (token) {
case "+": {
int a = stack.pop();
int b = stack.pop();
stack.push(b + a);
break;
}
case "-": {
int a = stack.pop();
int b = stack.pop();
stack.push(b - a);
break;
}
case "*": {
int a = stack.pop();
int b = stack.pop();
stack.push(b * a);
break;
}
case "/": {
int a = stack.pop();
int b = stack.pop();
stack.push(b / a);
break;
}
default:
stack.push(Integer.parseInt(token));
break;
}
}
return stack.pop();
}
}
本文主要給大家介紹瞭如何將中綴表示式轉化成字尾表示式,以及程式碼根據字尾表示式求值。本文所談到的問題可能相對於其他問題來說邏輯上可能更加複雜,需要大家自己閱讀和根據文字和圖進行理解。
以上就是本文所有的內容了,希望大家有所收穫,我是LeHung,我們下期再見!!!(記得點贊收藏哦!)
更多精彩內容合集可存取專案:https://github.com/Chang-LeHung/CSCore
關注公眾號:一無是處的研究僧,瞭解更多計算機(Java、Python、計算機系統基礎、演演算法與資料結構)知識。