[LeetCode] 由 「中綴表達式 --> 後綴表達式" 所想

如何利用棧解決問題。html

Ref: 如何在程序中將中綴表達式轉換爲後綴表達式?算法

本文的引伸:如何手寫語法分析器數據結構

 

 

實現調度場算法

 

「9+(3-1)*3+10/2」 --> 「9 3 1-3*+ 10 2/+」app

規則:

從左到右遍歷中綴表達式的每一個數字和符號,post

如果數字就輸出,即成爲後綴表達式的一部分;spa

如果符號,則判斷其與棧頂符號的優先級,.net

是右括號或優先級低於棧頂符號(乘除優先加減)code

    • 則棧頂元素依次出棧並輸出,
    • 並將當前符號進棧,

一直到最終輸出後綴表達式爲止。orm

 

舉個栗子:

1. 初始化一空棧,用來對符號進出棧使用。htm

2. 第一個字符是數字9,輸出9,後面是符號「+」,進

 

9+(3-1)*3+10/2」 --> 「9 3 1-3*+ 10 2/+」

3. 第三個字符是「(」,依然是符號,因其只是左括號,還未配對,故進棧。

4. 第四個字符是數字3,輸出,總表達式爲9 3,接着是「-」進棧。

「9+(3-1)*3+10/2」 --> 「9 3 1-3*+ 10 2/+」

5. 接下來是數字1,輸出,總表達式爲9 3 1,後面是符號「)」,此時,咱們須要去匹配此前的「(」,因此棧頂依次出棧,並輸出,直到「(」出棧爲止。此時左括號上方只有「-」,所以輸出「-」,總的輸出表達式爲9 3 1 -

6. 接着是數字3,輸出,總的表達式爲9 3 1 - 3 。緊接着是符號「*」,由於此時的棧頂符號爲「+」號,優先級低於「*」,所以不輸出,進棧。

「9+(3-1)*3+10/2」 --> 「9 3 1-3*+ 10 2/+」

7. 以後是符號「+」,此時當前棧頂元素比這個「+」的優先級高,所以棧中元素出棧並輸出(沒有比「+」號更低的優先級,因此所有出棧),總輸出表達式爲 9 3 1 - 3 * +;而後將當前這個符號「+」進棧。也就是說,前6張圖的棧底的「+」是指中綴表達式中開頭的9後面那個「+」,而下圖中的棧底(也是棧頂)的「+」是指「9+(3-1)*3+」中的最後一個「+」。

8. 緊接着數字10,輸出,總表達式變爲9 3 1-3 * + 10。

「9+(3-1)*3+10/2」 --> 「9 3 1-3*+ 10 2/+」

9. 最後一個數字2,輸出,總的表達式爲 9 3 1-3*+ 10 2

10. 因已經到最後,因此將棧中符號所有出棧並輸出。最終輸出的後綴表達式結果爲 9 3 1-3*+ 10 2/+

「9+(3-1)*3+10/2」 --> 「9 3 1-3*+ 10 2/+」
 

 

 

從剛纔的推導中你會發現,要想讓計算機具備處理咱們一般的標準(中綴)表達式的能力,最重要的就是兩步:
    1. 將中綴表達式轉化爲後綴表達式(棧用來進出運算的符號)。
    2. 將後綴表達式進行運算得出結果(棧用來進出運算的數字)。

整個過程,都充分利用了找的後進先出特性來處理,理解好它其實也就理解好了棧這個數據結構。

 

 

Python 代碼實踐

import logging

class Stack: 
    def __init__(self): 
        self.items = []

    def isEmpty(self):
        return self.items == []
        
    def push(self, item):
        logging.info("Info: push {}".format(item))
        self.items.append(item)

    def pop(self):
        if True == self.isEmpty():
            logging.info("Info: it's empty.")           
            return None
        return self.items.pop()

    def peek(self):
        if True == self.isEmpty():
            logging.info("Info: it's empty.")           
            return None
        return self.items[-1]

    def size(self):
        return len(self.items)

    def __str__(self): 
        return "{}".format(self.items)


logging.basicConfig(level=logging.INFO)

# 「9+(3-1)*3+10/2」 --> 「9 3 1-3*+ 10 2/+」


def infixToPostfix(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":
            postfixList.append(token)
        elif token == '(':
            opStack.push(token)
        elif token == ')':
            # do...while, 把括號區間的符號都輸出
            while True: 
                topToken = opStack.pop()
                if topToken == '(':
                    break
                postfixList.append(topToken)
        else:
            # 由於符號只有兩個優先級別,
            # +來了,確定弱於棧底元素;」先處理遺留問題」再入棧
            # *來了,要麼弱於棧底元素;要麼更厲害,但反正仍是要入棧
            while (not opStack.isEmpty()) and (prec[opStack.peek()] >= prec[token]):
                # 這裏就是「處理遺留問題」
                postfixList.append(opStack.pop())
            opStack.push(token)

    # 「處理遺留問題」
    while not opStack.isEmpty():
        postfixList.append(opStack.pop())

    return " ".join(postfixList)

print(infixToPostfix("A * B + C * D")) print(infixToPostfix("( A + B ) * C - ( D - E ) * ( F + G )"))

  

End. 

相關文章
相關標籤/搜索