編譯原理中的逆波蘭表示式(資料流圖中運算變數的流程)
其中,逆波蘭表示式在編譯技術中有著普遍的應用。
演算法: 一、 將中綴表示式轉換成字尾表示式演算法: 1、從左至右掃描一中綴表示式。 2、若讀取的是運算元,則判斷該運算元的型別,並將該運算元存入運算元堆疊 3、若讀取的是運算子 (1) 該運算子為左括號"(",則直接存入運算子堆疊。 (2) 該運算子為右括號")",則輸出運算子堆疊中的運算子到運算元堆疊,直到遇到左括號為止。 (3) 該運算子為非括號運算子: (a) 若運算子堆疊棧頂的運算子為括號,則直接存入運算子堆疊。 (b) 若比運算子堆疊棧頂的運算子優先順序高或相等,則直接存入運算子堆疊。 (c) 若比運算子堆疊棧頂的運算子優先順序低,則輸出棧頂運算子到運算元堆疊,並將當前運算子壓入運算子堆疊。 4、當表示式讀取完成後運算子堆疊中尚有運算子時,則依序取出運算子到運算元堆疊,直到運算子堆疊為空。所謂的標準的表示式如"A+B",它在數學上學名叫中綴表示式(Infix Notation),原因是:
運算子號在兩個運算物件的中間。
其優勢: 在於只:用兩種簡單操作,入棧和出棧就可以搞定任何普通表示式(僅包含:+-*/和()的表示式)的運算。
其基本運算方式 :如果當前字元為變數或者為數字,則壓棧,如果是運算子,則將棧頂兩個元素彈出作相應運算,結果再入棧,最後當表示式掃描完後,棧裡的就是結果。
為什麼說逆波蘭式產生機器碼的效率高:因為逆波蘭式非常易於計算機的處理。原因是這樣的。舉例:
3 32 + 5 3 * -
12 34 2 - * 8 /
乍一看上面兩個式子很奇怪,是嗎?它們就是一種表示式的記法——逆波蘭表示式。
現在,準備一個很窄的圓筒,筒是有底的(其實是堆疊)。再做幾個圓紙片,在紙片上依次寫上“3”“32”“+”“5”“3”“*”“-”,記住,每個紙片上要麼只寫一個數,要麼只寫一個運算子號,把它們按上面的順序排好。好,現在仔細聽我說,按順序一個接一個地拿起小圓紙片,反覆執行以下幾個規則:
1. 如果你拿著的是一個數,不多說,直接把它放進圓筒;
2. 如果你拿著的是一個運算子號,不要把它放進去。先從圓筒裡取出兩個數(當然是先取最上而的啦,筒很細的),然後處這兩個數作運算子號指定的運算,並把結果寫在一張新的紙片上,然後放進筒裡。比如你拿著的是“+”,你要依次取出“32”和“3”,讓它們相加,得“35”,把“35”寫在一張新紙片上(現在“34”和“12”可以扔掉了),並把這張新紙片放進圓筒。
當圓筒裡只有一個數時,你就可以停下來了,我猜這個數是20,沒錯,這就是這個表示式的值!
我們剛才操作的,其實就是一個“棧”,棧是一種資料結構,具有一個性質——後進先出(LIFO——Last Input First Output),你已經深有體會了,就像一摞盤子,你只能從最上面的開始取,放的時候也只能放在最上面。放進去的動作叫做“入棧”,取出來叫做“彈出”。以後你就可以把棧想像成一摞盤子,或是上面說的小圓筒和小紙片,棧就是這麼簡單!
逆波蘭表示式雖然看起來比較繁瑣,其實在計算機中很有用。計算機可不知道先乘除後加減,先括號內後括號外
將一箇中綴表示式 轉換成 逆波蘭式的演算法: 結合一個具體例子分析如下:
a)給出一箇中綴表示式1*(2+3)
b)系統先定義兩個先進後出的堆疊:運算子號棧(簡稱入棧in),字尾表示式輸出符號棧(簡稱出棧out)
c)系統按從左至右的順序讀取中綴表示式
d)讀入數字直接壓入出棧(out)
e)讀入第一個運算子直接壓入入棧(in)
f)讀入"("直接壓入入棧(in)。 按上述規則讀取若干次後,若,此時兩棧的資料為: in 【*,( 】 ; out 【1,2】,開始讀取的第二個的運算子"+",並將之與入棧(in)中的棧頂運算子"("進行比較,
g)高於棧頂運算子級別的算符直接進棧,低於或等於棧頂級別的要將入棧(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,+,* |
將中綴表示式轉換成逆波蘭表示式過程中,特別要注意對於中綴標到式中括號的處理。
1、要注意的,如果算符是"(",無論入棧中棧頂級別(只看棧頂)為何直接入棧,所以,“(”的等級
只用於對其後入棧的算符進行優先順序比較,在“(”入棧時是無視優先順序的。(博主強烈提醒!!!!!!!!!!!!!!!!!!!)
2、在遇到")"時候找到最後進入的"(",並把"("前面所有的符號都壓入出棧。不能僅憑運算子的級別來判斷。
將一個 逆波蘭式 倒轉回 中綴表示式 的演算法:
這個就相當簡單了,就是一個機械的入堆疊出堆疊的操作,
1)設定一個堆疊,將逆波蘭式從左到右開始進行出入堆疊操作,還以上例為例:1,2,3,+,*
2)遇到數字直接壓棧;例如,上例逆波蘭先進行三次入棧操作,堆疊的格局是: 1,2,3(棧頂);
3)遇到算符,將堆疊中的兩個數字出棧。 如,讀到+號後,2,3出棧,進行運算。注意,出棧時先出棧的元素是右運算元,後出棧的是左運算元,上例是2+3,不是3+2;
4)將運算的結果作為新的運算元,壓入堆疊中。如運算結果(2+3)入棧,堆疊格局:1,(2+3);
5)反覆1-4的操作,得到的中序表示式就是: 1*(2+3);
中序表式生成的逆波蘭式唯一嗎?:
是唯一的,和固定形式的中序表示式一一對應,但,請注意這個概念,
例如: a+(b-c)*d 和 (b-c)*d+a 和 a+d*(b-c) 的值是完全一樣的。但是,他們的中序形式不同,
產生的逆波蘭式必然是不同的。
a+(b-c)*d : abc-d*+
(b-c)*d+a : bc-d*a+
a+d*(b-c) : adbc-*+
相關推薦
編譯原理中的逆波蘭表示式(資料流圖中運算變數的流程)
表示式一般由運算元(Operand)、運算子(Operator)組成,例如算術表示式中,通常把運算子放在兩個運算元的中間, 這稱為中綴表示式(Infix Expression),如A+B。 波蘭數學家Jan Lukasiewicz提出了另一種數學表示法,它有兩種表示形
C#資料結構與算法系列(十):逆波蘭計算器——逆波蘭表示式(字尾表示式)
1.介紹 字尾表示式又稱逆波蘭表示式,與字首表示式相似,只是運算子位於運算元之後 2.舉例說明 (3+4)*5-6對應的字尾表示式就是3 4 +5 * 6 - 3.示例 輸入一個逆波蘭表示式(字尾表示式),使用棧(Stack),計算其結果 思路分析: 從左至右掃描表示式,遇到數字時,將數字壓入堆疊,遇到運算
Python 藉助逆波蘭表示式(字尾表示式)實現簡單計算器
Python 藉助逆波蘭表示式(字尾表示式)實現簡單計算器 文章目錄 Python 藉助逆波蘭表示式(字尾表示式)實現簡單計算器 0. 參考資料 1. 中綴表示式轉字尾表示式 2. 字尾表示式的求值 3. Python
Java實現逆波蘭表示式(Evaluate Reverse Polish Notation)
逆波蘭表示式 定義:傳統的四則運算被稱作是中綴表示式,即運算子實在兩個運算物件之間的。逆波蘭表示式被稱作是字尾表示式,表示式實在運算物件的後面。 逆波蘭表示式: a+b ---> a,b,+
逆波蘭表示式(字尾表示式)的計算
已知12*(3+4)- 6+8/2的字尾表示式為:12 3 4 + * 6 - 8 2 / + 字尾表示式計算時,所有運算按照運算子出現的順序,嚴格從左到右,每個操作符取前兩個運算元進行運算,運算後的結果仍然作為下次的運算元。 那如果已知字尾表
編譯原理:將a+d*(b-c) 寫成逆波蘭表示式
逆波蘭表示式示例 1. a+b 改為 ab+ 2. (a+b)*(c+d) 改為 ab+cd+* 3. a+d*(b-c) 改為 adbc-*+ 逆波蘭表示式又叫做字尾表示式,顧
資料結構--中綴表示式轉為字尾表示式(逆波蘭表示式)
中綴表示式是一個通用的算術或邏輯公式表示方法。操作符是以中綴形式處於運算元中間。例如:3*4+3-1; 字尾表示式不包含括號,運算子放在兩個運算物件的後面,所有的計算按運算子出現的順序,嚴格從左向右(不再考慮運算子的優先規則)例如:(2+1)*3,即2 1 + 3 * (以
LeetCode150.逆波蘭表示式求解(Evaluate Reverse Polish Notation)
題目描述 根據逆波蘭表示法,求表示式的值。 有效的運算子包括 +, -, *, / 。每個運算物件可以是整數,也可以是另一個逆波蘭表示式。 說明: 整數除法只保留整數部分。 給定逆波蘭表示式總是有效的。換句話說,表示式總會得出有效數值且不存在除數為 0 的情況。
中綴表示式轉化為字尾表示式(逆波蘭表示式)
1.將中綴表示式轉化為字尾表示式 字尾表示式也叫作逆波蘭表示式,主要是運用棧的後進先出思想,下面就講講我自己的思考, 假設中綴表示式為:2*(2+1)-6(4-2)#,則字尾表示式為:2 2 1 + * 6 4 2 - / -; 首先依次遍歷中綴表示式,遇到運算元字元則直接輸出(數字字元
逆波蘭式(字尾表示式)的表達求值
逆波蘭表示式求值 [編輯]虛擬碼 while有輸入符號 讀入下一個符號IF是一個運算元 入棧ELSE IF是一個操作符 有一個先驗的表格給出該操作符需要n個引數IF堆疊中少於n個運算元 (錯誤) 使用者沒有輸入足夠的運算元Else,n個操作數出棧計算操作符。將計算所得的
LeetCode: Evaluate Reverse Polish Notation(計算逆波蘭表示式)兩種方法
題目描述Evaluate the value of an arithmetic expression in Reverse Polish Notation.Valid operators are +, -, *, /. Each operand may be an integ
逆波蘭表示式原理實現
解析原理如下: (1) 該運算子為左括號"(",則直接存入運算子堆疊。 (2) 該運算子為右括號")",則輸出運算子堆疊中的運算子到運算元堆疊,直到遇到左括號為止,此時拋棄該左括號。 (3) 該運算子為非括號運算子: (a) 若運算子堆疊棧頂的
基於逆波蘭表示式的公式解析器-演算法和思路(一)
背景: 最近專案需要自己完成Excel的公式解析和求值,在Java中可以使用POI解析Excel公式然後求值。但是專案需要JS端和Java後端均需要支援公式解析,所以就需要自己寫一套了。
將中綴表示式轉化為逆波蘭式(c++實現)
<pre name="code" class="cpp">/************************************************************************* > File Name: ReversePol
字尾表示式(逆波蘭表示式)
逆波蘭表示式又叫做字尾表示式。在通常的表示式中,二元運算子總是置於與之相關的兩個運算物件之間,這種表示法也稱為中綴表示。波蘭邏輯學J.Lukasiewicz於1929年提出了另一種表示表示式的方法,按此方法,每一運算子都置於其運算物件之後,故稱為字尾表示。 表
JavaScript中綴表達式轉為逆波蘭式(四則運算)
。。 刪除 並且 asc 情況 暫存 運算符 pan true 實現過程: 1.首先創建兩個空數組,result用來存放結果,temp用來存放符號;再創建一個符號集ops存放+-*/符號 2.轉表達式字符為數組,開始遍歷數組 3.如果遇到運算符,直接推入結果數組 4.遇到括
C語言_解決括號匹配問題和逆波蘭表示式求值為題
##1、括號匹配問題: 解決思路: void MatchBrackets (const char* str) { char* per = NULL; int i = 0; Stack s; assert (str != NULL); InitStack (&s);
leet150. 逆波蘭表示式求值
題目: 求在 逆波蘭表示法 中算術表示式的值。 有效的運算子號包括 +, -, *, / 。每個運算物件可以是整數,也可以是另一個逆波蘭計數表達。 例如: ["2", "1", "+", "3", "*
LeetCode:逆波蘭表示式求值【150】
LeetCode:逆波蘭表示式求值【150】 題目描述 根據逆波蘭表示法,求表示式的值。 有效的運算子包括 +, -, *, / 。每個運算物件可以是整數,也可以是另一個逆波蘭表示式。 說明: 整數除法只保留整數部分。 給定逆波蘭表示式總是
佇列&棧//逆波蘭表示式求值
根據逆波蘭表示法,求表示式的值。 有效的運算子包括 +, -, *, / 。每個運算物件可以是整數,也可以是另一個逆波蘭表示式。 說明: 整數除法只保留整數部分。 給定逆波蘭表示式總是有效的。換句話說,表示式總會得出有效數值且