數據結構の學習(五):將中綴表達式轉換爲後綴表達式及求值

(1)給表達式加括號(2)創建解析樹表達式(3)樹的後序遍歷,生成後綴表達式(4)後綴表達式求值。經過前面幾個步驟的洗禮,相信你內心充滿了喜悅和興趣。現在我們只需要將後綴表達式計算輸出即可,然而可怕的是:-$

不借助樹我們也能輕鬆實現上述過程。這種方法便是逆波蘭表示法(Reverse Polish Network)。我們將着重介紹這一神奇的方法。


不幸的是,筆者的博客將不會有完整代碼(示範代碼除外),所有代碼均已上傳到碼雲上。如果時間和精力允許的話,強烈建議你根據思路,手動寫一遍,相信你會感覺到全身毛孔舒張而不是想砸電腦的快感。

好了,按照慣例,我們先介紹一些術語。


棧: 存儲數據的結構,講究“先進後出”,即最先進棧的數據,最後出棧;有順序存儲和鏈式存儲兩種。
隊列:存儲數據的結構,它只允許在表的前端(front)進行刪除操作,而在表的後端(rear)進行插入操作,和棧一樣,隊列是一種操作受限制的線性表。進行插入操作的端稱爲隊尾,進行刪除操作的端稱爲隊頭。

我們建立一個堆棧Stack()(用於存放運算符)和一個Queue()(用於存放後綴表達式)。思路是這樣的,我們依次遍歷中綴表達式(可以不帶括號),記爲i。

(1)遇到操作數直接輸出到隊列中。

(2)遇到'('則直接壓入棧,因爲它的優先級最小。

(3)遇到')',則開始出棧,將出棧的元素依次加入到隊列中,直到遇到'('爲止。

(4)遇到運算符,則比較複雜了。還好,你是一個心細如絲的人,你不會放過一個可能導致程序漏洞的bug。我們希望隊列前面是最先被計算(優先級最高)的式子,比如1+(2+3)*4-5,我們得到後綴表達式爲123+4*+5-。因此我們必須把i和棧頂元素作比較:如果i優先級大於棧頂元素,則可以直接入棧(如果棧是空的,我們得往棧壓入一個運算符,不用比較);否則,將Stack出棧,輸出到隊列中,直到i優先級大於棧頂或者棧空爲止。

(5)完成遍歷後,若棧內還有元素,將它們依次輸出到隊列即可。但需要注意的是,我們此時將隊列輸出是一個逆序的後綴表達式。

如果你覺得理解起來比較吃力,我將畫出這個過程,(人們總是喜歡配圖的算法博客:-^),以1+(2+3)*4-5爲例:

相信結合上述圖,你已經熟悉了這種RPN。下面講解如何計算後綴表達式。

從左到右遍歷後綴表達式,我們準備一個數字棧s_num

(1)若遇到數字則壓入s_num。

(2)遇到 運算符則,彈出s_num最上面兩個元素,與操作符一起運算。將計算的結果重新壓入棧。這一步很容易被未來的軟件工程獅忽視。如此便計算出後綴表達式的結果。當然,遇到原理性問題比如1/0和log0和0^0,你的程序應該也能拋出相應的異常。

 

實現上述算法的好處是,你可以將二叉樹得到的結果和RPN法得到的結果進行對比,如果兩者不一樣,一定是你的樹出了問題。要麼是給表達式加括號出了問題,要麼是表達式解析樹建立出了問題。筆者檢測出無數bug也是這個原因。

下面是筆者一些測試數據,你在我的碼雲中也能看到:

編號

測試數據

TREE

TREELESS(RPN)

1

1

1.0

1.0

2

1+1

2.0

2.0

3

1+1*3

4.0

4.0

4

5/(1+5/6*3-3%2)*0.5+2/3+(2+3)/3

3.333333333333333

3.333333333333333

5

2^5

32.0

32.0

6

2%5^4

2.0

2.0

7

(((3*(4+(66.6/6)))+(7*(9+(((4+2)%2)/2))))+(((3/2)-1)/0.5))/(5^2)

4.372

4.372

8

4.2/(-3.5*+2+2^-2.2/4*5%6)+3-(-4.5)

6.875738797245451

6.875738797245452

9

1/0

RAISE ERROR

RAISE ERROR

10

1/(2-1)

1

1

11

(5/6+1)/0.5^5+2

60.66666666666667

60.66666666666667

12

(5/0.5^5%2*3+1)/0.5^5%2*3+1

1.0

1.0

參考資料:https://www.cnblogs.com/icodes8238/p/12243275.html 

希望筆者的博客能對你有幫助,如果有問題,歡迎留言,或者email [email protected]! 當然你給我Gitee ,Fork&Star一下,筆者也是不勝感激的!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章