中綴表示式 轉換為 字首 字尾表示式

2021-08-10 10:30:29 字數 3890 閱讀 3895

考慮表示式a + b * ca b c * +是等價的字尾表示式。 我們已經注意到,運算元 a,b 和 c 保持在它們的相對位置。只有操作符改變位置。再看中綴表示式中的運算子。從左到右出現的第乙個運算子為 +。 然而,在字尾表示式中,+ 在結束位置,因為下乙個運算子 * 的優先順序高於加法。 原始表示式中的運算子的順序在生成的字尾表示式中相反。

當我們處理表示式時,操作符必須儲存在某處,因為它們相應的右運算元還沒有看到。 此外,這些儲存的操作符的順序可能由於它們的優先順序而需要反轉。這是在該示例中的加法和乘法的情況,由於加法運算子在乘法運算子之前,並且具有較低的優先順序,因此需要在使用乘法運算子之後出現。 由於這種順序的反轉,考慮使用棧來儲存運算子直到用到它們是有意義的。

(a + b)* c的情況會是什麼樣呢? 回想一下,a b + c *是等價的字尾表示式。從左到右處理此中綴表示式,我們先看到+。 在這種情況下,當我們看到*+已經放置在結果表示式中,由於括號它的優先順序高於*。 我們現在可以開始看看轉換演算法如何工作。當我們看到左括號時,我們儲存它,表示高優先順序的另乙個運算子將出現。該操作符需要等到相應的右括號出現以表示其位置(回憶完全括號的演算法)。 當右括號出現時,可以從棧中彈出操作符。

當我們從左到右掃瞄中綴表示式時,我們將使用棧來保留運算子。這將提供我們在第乙個例子中注意到的反轉。 堆疊的頂部將始終是最近儲存的運算子。每當我們讀取乙個新的運算子時,我們需要考慮該運算子如何與已經在棧上的運算子(如果有的話)比較優先順序。

假設中綴表示式是乙個由空格分隔的標記字串。 操作符標記是*,/,+-,以及左右括號。運算元是單字元 a,b,c 等。 以下步驟將字尾順序生成乙個字串。

建立乙個名為 opstack 的空棧以儲存運算子。給輸出建立乙個空列表。

通過使用字串方法拆分將輸入的中綴字串轉換為標記列表。

從左到右掃瞄標記列表。

當輸入表示式被完全處理時,檢查 opstack。仍然在棧上的任何運算子都可以刪除並加到輸出列表的末尾。

figure 展示了對表示式a * b + c * d的轉換演算法。注意,第乙個*在看到+運算子時被刪除。另外,當第二個 * 出現時,+保留在棧中,因為乘法優先順序高於加法。在中綴表示式的末尾,棧被彈出兩次,刪除兩個運算子,並將+作為字尾表示式中的最後乙個運算子。

figure

為了在 python 中編寫演算法,我們使用乙個名為 prec 的字典來儲存操作符的優先順序。這個字典將每個運算子對映到乙個整數,可以與其他運算子的優先順序(我們使用整數3,2和1)進行比較。左括號將賦予最低的值。這樣,與其進行比較的任何運算子將具有更高的優先順序,將被放置在它的頂部。第15行將運算元定義為任何大寫字元或數字。完整的轉換函式見 activecode 1。

from pythonds.basic.stack import stack

definfixtopostfix

(infixexpr):

prec = {}

prec["*"] = 3

prec["/"] = 3

prec["+"] = 2

prec["-"] = 2

prec["("] = 1

opstack = stack()

postfixlist =

tokenlist = infixexpr.split()

for token in tokenlist:

if token in

"abcdefghijklmnopqrstuvwxyz"

or token in

"0123456789":

elif token == '(':

opstack.push(token)

elif token == ')':

toptoken = opstack.pop()

while toptoken != '(':

toptoken = opstack.pop()

else:

while (not opstack.isempty()) and \

(prec[opstack.peek()] >= prec[token]):

opstack.push(token)

while

not opstack.isempty():

return

" ".join(postfixlist)

print(infixtopostfix("a * b + c * d"))

print(infixtopostfix("( a + b ) * c - ( d - e ) * ( f + g )"))

執行結果如下

>>> infixtopostfix("( a + b ) * ( c + d )")

'a b + c d + *'

>>> infixtopostfix("( a + b ) * c")

'a b + c *'

>>> infixtopostfix("a + b * c")

'a b c * +'

>>>

首先構造乙個運算子棧,然後從右至左掃瞄中綴表示式。如果是運算元,則直接輸出,作為字首表示式的乙個直接轉換表示式temp(最後,字首表示式由該表示式翻轉得到);如果是運算子,則比較優先順序:若該運算子優先順序大於等於棧頂元素,則將該運算子入棧,否則棧內元素出棧並加到temp表示式尾端,直到該運算子大於等於棧頂元素的優先順序時,再將該運算子壓入棧中。遇到右括號直接壓入棧中,如果遇到乙個左括號,那麼就將棧元素彈出並加到temp表示式尾端,但左右括號並不輸出。最後,若運算子棧中還有元素,則將元素一次彈出並加到temp表示式尾端,最後一步是將temp表示式翻轉。

假定有中綴表示式1 + (( 2 + 3)* 4 ) – 5

其過程如下圖所示:

和轉為字尾不同之處在於:

def

midtopost

(expr):

prec={}

prec["*"] = 3

prec["/"] = 3

prec["+"] = 2

prec["-"] = 2

prec["("] = 1

opstack = stack() # 用於儲存符號

postfixlist = # 儲存最終的表示式

tokenlist = expr.split()

tokenlist.reverse()

for token in tokenlist:

if token in

"abcdefghijklmnopqrstuvwxyz"

or token in

"0123456789":

elif token == ')':

opstack.push(token)

elif token == '(':

toptoken = opstack.pop()

while toptoken != '(':

toptoken = opstack.pop()

else:

while (not opstack.isempty()) and (prec[opstack.peek()] > prec[token]):

opstack.push(token)

while

not opstack.isempty():

postfixlist.reverse()

return

" ".join(postfixlist)

中綴表示式轉換為字尾表示式

今天我們課前談一談,要說點什麼好呢?最近小甲魚發現,很多魚油在學習資料結構和演算法的時候積極性已經開始有點下降了。甚至很多朋友懷疑資料結構和演算法到底有沒有用?實話說,在大廈的防震設計 消除疾病 防止水源枯竭這些實際問題中,很遺憾,資料結構和演算法幾乎起不到任何直接作用。那為什麼我們要學呢?很簡單,...

中綴表示式轉換為字尾表示式

字尾表示式也叫逆波蘭表示式,其求值過程可以用到棧來輔助儲存。假定待求值的字尾表示式為 6 5 2 3 8 3 則其求值過程如下 1 遍歷表示式,遇到的數字首先放入棧中,此時棧如下所示 2 接著讀到 則彈出3和2,執行3 2,計算結果等於5,並將5壓入到棧中。3 讀到8,將其直接放入棧中。4 讀到 彈...

中綴表示式轉換為字尾表示式

字尾表示式也叫逆波蘭表示式,其求值過程可以用到棧來輔助儲存。假定待求值的字尾表示式為 6 5 2 3 8 3 則其求值過程如下 1 遍歷表示式,遇到的數字首先放入棧中,此時棧如下所示 2 接著讀到 則彈出3和2,執行3 2,計算結果等於5,並將5壓入到棧中。3 讀到8,將其直接放入棧中。4 讀到 彈...