逆波蘭表示式被廣泛應用於編譯原理中,但是近來在研究計算一元一次方程的時候發現通過逆波蘭演算法計算一元一次方程會更簡單,原因是逆波蘭表示式有乙個其他的演算法不能比擬的優點–拆括號(關於一元一次方程的演算法程式,我會在以後陸續登載)。
標準的表示式如"a+b",在數學上學名叫中綴表示式(infix notation),原因是運算符號在兩個運算物件的中間。相對應的還有字首表示式(prefix notation),如:"+ - a * b c d",轉換成中綴表示式為:"a - b * c + d";字尾表示式(postfix notation),比如前所述的中綴表示式轉換為字尾表示式為:"a b c * - d +"。為了紀念波蘭數學家魯卡謝維奇(jan lukasiewicz),字首表示式被稱作波蘭表示式,字尾表示式稱為逆波蘭表示式(reverse polish notation)。
字尾表示式的優點是顯而易見的,編譯器在處理時候按照從左至右的順序讀取逆波蘭表示式,遇到運算物件直接壓入堆疊,遇到運算子就從堆疊提取後進的兩個物件進行計算,這個過程正好符合了計算機計算的原理。
字尾表示式比字首表示式更加易於轉換,並且它的最左面一定為數字,這一點在實際程式設計的時候就會體會到它的好處了。
逆波蘭表示式有乙個更大的優點,就是拆括號,根據運算子的級別將中綴表示式轉換成逆波蘭表示式後,運算順序就已經替代了運算子的級別,這樣也避免了括號提高運算級別的特殊處理。
現在我就先簡單介紹一下從中綴表示式轉換為逆波蘭表示式的標準演算法。
a)給出乙個中綴表示式1*(2+3)
b)系統先定義兩個先進後出的堆疊:運算符號棧(簡稱入棧in),字尾表示式輸出符號棧(簡稱出棧out)
c)系統按從左至右的順序讀取中綴表示式
d)讀入數字直接壓入出棧(out)
e)讀入第乙個運算子直接壓入入棧(in)
f)讀入"("直接壓入入棧(in),此時兩棧的資料為:in 1 ; out *,(
e)將第二次讀取的運算子"+"與入棧中的棧頂運算子"("進行比較,高於棧頂級別的直接進 棧,低於或等於棧頂級別的要將入棧in解棧(即出棧),按次壓入出棧中。比如現在入棧的運算順序為(,*,/,此時若系統讀取的運算子為+,級別比/要 低,此時要按/,*的順序壓入出棧out中,並在入棧中釋放/和*符號,最後得到 in ( ; out /,*的結果。
f)最後讀取")"時要找到入棧in中最近的"(",將其前面所有符號全部按後進先出的順序壓入出棧,並解壓,"("與")"抵消。此時兩棧的資料為:in 1,2,3,+ ; out *
g)系統讀取中綴表示式結束後將入棧in中的所有符號按後進先出的順序全部解壓,並依次壓入出棧out中,最後出棧的結果就應該為1,2,3,+,*
h)按先進先出的順序將出棧out解壓得到字尾標準表示式1,2,3,+,*
兩個堆疊先後資料情況:
in out 1*
1*,(
1*,(
1,2*,(,+
1,2*,(,+
1,2,3
* 1,2,3,+
1,2,3,+,*
將中綴表示式轉換成逆波蘭表示式過程中,要注意的是"("無論入棧中級別為何直接入棧,在遇到")"時候找到最後進入的"(",並把"("前面所有的符號都壓入出棧。我在程式設計中就犯過錯誤,僅憑運算子的級別來判斷,結果出現錯誤的結果。
在上面簡單概述了逆波蘭表示式的用途,中綴表示式轉換逆波蘭表示式的標準演算法,還有逆波蘭表示式的計算方法。下面,我將給出中綴表示式轉換逆波蘭表示式時各運算子的運算級別。
運算子的運算級別即方程式運算的先後級別,如下:
運算子 級別
空格 0) 1
( 2+,- 3
*,/ 4
運算物件
-1我現在給出中綴表示式轉換逆波蘭表示式的c#源**,該**在.net2005執行通過。由於時間原因部分**未作優化,希望有興趣的朋友能請給我提出更好的建議
using system;
using system.collections.generic;
using system.text;
using system.collections;
namespace test
///
/// 操作符運算級別
///
/// 操作符
/// 操作運算子,空格返回0,出錯返回-1
private int operatorlevel(string stroperator)
}///
/// 將中綴表示式轉換為逆波蘭表示式
///
/// ession">標準中綴表示式
/// 標準逆波蘭表示式
public string rpnexpression(string expression)
);int intnum = strnum.getlength(0);
//操作運算子堆疊
stack oper = new stack();
//定義輸出堆疊
stack output = new stack();
//定義字首表示式字元讀取指標
int i = 0;
//定義當前讀取數字陣列指標
int n = 0;
//定義操作運算子級別函式
operator op = new operator();
//輸出堆疊的大小
int intstackcount = 0;
//從左到右讀取字首表示式
while (i < strexpression.length)
else if (intlevel == -1)
//數字直接推入輸出堆疊}}
else //操作字元根據運算字元級別推入運算子堆疊
else
else
}else}}
}}}else
i++;}}
//形成逆波蘭表示式輸出字串
object stroutput = output.toarray();
string str = convert.tostring(stroutput[stroutput.getlength(0) - 1]);
for (int m = stroutput.getlength(0) - 2; m >= 0; m--)
}return str;
}catch
}///
/// 解逆波蘭表示式
///
/// ession">標準逆波蘭表示式
/// 逆波蘭表示式的解
public double complierpnexp(string expression)
);int intlenth = strnum.getlength(0);
//定義數字堆疊
stack number = new stack();
for (int i = 0; i < intlenth; i++)
else if (intlevel > 2)}}
}double d = convert.todouble(number.pop());
number.clear();
return d;
}catch
}///
/// 計算逆波蘭表示式
///
/// 最後壓入數字堆疊的數字
/// 首先壓入數字堆疊的數字
/// 操作運算子
/// 返回計算結果
private double complierpnexp(double dlastin, double dfirstin, string oper)}}
}到此逆波蘭表示式已經全部搞定,現在我可以通過將中綴表示式轉換成逆波蘭表示式再計算,不會擔心括號的問題。
一元多次方程乃至一元多次方程的解都迎刃而解。
出處 :
逆波蘭表示式 中綴表示式 字尾表示式
1 我們這裡要實現的是 將中綴表示式轉換成字尾表示式,然後再計算最終結果,參考部落格。具體轉化演算法如下 中綴表示式a b c d e f g,其轉換成字尾表示式則為abc de f g 轉換過程需要用到棧,具體過程如下 1 如果遇到運算元,我們就直接將其輸出。2 如果遇到操作符,則我們將其放入到棧...
逆波蘭表示式 中綴表示式 字尾表示式
1 我們這裡要實現的是 將中綴表示式轉換成字尾表示式,然後再計算最終結果,參考部落格。具體轉化演算法如下 中綴表示式a b c d e f g,其轉換成字尾表示式則為abc de f g 轉換過程需要用到棧,具體過程如下 1 如果遇到運算元,我們就直接將其輸出。2 如果遇到操作符,則我們將其放入到棧...
中綴表示式轉逆波蘭表示式
op icp064 21isp015 36思路假設表示式為string ex a b c d 將表示式處理為 a b c d 以 做末尾標識,初始時 棧s 中放入乙個 int i 0 icp表示表示式當前掃瞄項的字元的優先順序,isp表示棧頂操作符的優先順序 優先順序表如上 當 棧非空 或 當前掃瞄...