二叉樹的簡單應用--表示式樹
表示式樹
算數表示式是分層的遞迴結構,一個運算子作用於相應的運算物件,其運算物件又可以是任意複雜的表示式。二叉樹的遞迴結構正好用來表示這種表示式。下面只討論二元表示式。
二元表示式可以很自然的聯絡到二叉樹:以基本運算物件作為葉節點中的資料;以運算子作為非葉節點中的資料,其兩棵子樹是它的運算物件,子樹可以是基本運算物件,也可以是複雜表示式。如圖是一個表示式樹。
字首、中綴和字尾表示式
中綴表示式(中綴記法)
我們平時縮寫的表示式,將運算子寫在兩個運算元中間的表示式,稱作中綴表示式。在中綴表示式中,運算子有不同的優先順序,圓括號用於改變運算順序,這使得運算規則比較複雜,求值過程不能直接從左到右順序進行,不利於計算機處理。
字尾表示式
將運算子寫在兩個運算元之後的表示式稱作字尾表示式。字尾表示式中沒有括號,從而運算子沒有優先順序。字尾表示式的求值過程能夠嚴格按照從左到右的順序進行,有利於計算機處理。
字首表示式
字首表示式是將運算子寫在兩個運算元之前的表示式。和字尾表示式一樣,字首表示式沒有括號,運算子沒有優先順序,能嚴格按照從右到左的順序計算。
另外,算式表示式和表示式樹的關係如下:
- 表示式樹的先根遍歷:字首表示式
- 表示式樹的中根遍歷:中綴表示式
- 表示式樹的後根遍歷:字尾表示式
表示式的轉換
利用表示式樹
給定一個表示式的中綴形式:(4+1*(5-2))-6/3
首先將每個運算加上括號,區分優先順序,得到(4+(1*(5-2)))-(6/3)
括號外的-優先順序最低,作為根節點,(4+(1*(5-2)))作為左子樹,(6/3)作為右子樹;
遞迴的轉換4+(1*(5-2)),+最為根節點,4是左子樹,(1*(5-2))是右子樹。*是右子樹的根節點,1是左子樹,(5-2)是右子樹。最後計算(5-2),-是根節點,5是左子樹,2是右子樹。得到的表示式樹如上圖。
構造好表示式樹之後,字首表示式和中綴表示式可根據先根遍歷和後根遍歷得到。
字首表示式:- + 4 * 1 - 5 2 / 6 3
字尾表示式:4 1 5 2 - * + 6 3 / -
利用棧
將中綴表示式轉換為字尾表示式
step1:初始化一個棧和一個字尾表示式字串
step2:從左到右依次對中綴表示式中的每個字元進行以下處理,直到表示式結束
- 如果字元是‘(’,將其入棧
- 如果字元是數字,新增到字尾表示式的字串中
- 如果字元是運算子,先將棧頂優先順序不低於該運算子的運算子出棧,新增到字尾表示式中,再將該運算子入棧。當‘(’在棧中是,優先順序最低
- 如果字元是‘)’,將棧頂元素出棧,新增到字尾表示式中,直到出棧的是‘(’
step3:如果表示式結束,但棧中還有元素,將所有元素出棧,新增到字尾表示式中
例如給定一個表示式的中綴形式:(4+1*(5-2))-6/3,棧中和表示式的變化如下表所示:
|掃描到的元素|棧|字尾表示式|說明|
掃描到的元素 | 棧 | 字尾表示式 | 說明 |
---|---|---|---|
( | ( | 將(入棧,表示式空 | |
4 | ( | 4 | 將4加入表示式 |
+ | ( + | 4 | 將+入棧 |
1 | ( + | 4 1 | 將1加入表示式 |
* | ( + * | 4 1 | 將*入棧 |
( | ( + * ( | 4 1 | 將(入棧 |
5 | ( + * ( | 4 1 5 | 將5加入表示式 |
- | ( + * ( - | 4 1 5 | 將-入棧 |
2 | ( + * ( - | 4 1 5 2 | 將2 加入表示式 |
) | ( + * | 4 1 5 2 - | -出棧,加入表示式 |
) | 4 1 5 2 - * + | *和+出棧,加入表示式,棧空 | |
- | - | 4 1 5 2 - * + | -入棧 |
6 | - | 4 1 5 2 - * + 6 | 6加入表示式 |
/ | -/ | 4 1 5 2 - * + 6 | /入棧 |
3 | -/ | 4 1 5 2 - * + 6 3 | 3加入表示式 |
4 1 5 2 - * + 6 3 / - | 表示式掃描結束,將棧中元素加入表示式 |
最後得到字尾表示式為4 1 5 2 - * + 6 3 / -
將中綴表示式轉換為字首表示式
中綴表示式轉換到字首表達的方法和轉換到字尾表示式過程一致,細節上有所變化
step1:初始化兩個棧s1 和s2
step2:從右到左依次對中綴表示式中的每個字元進行以下處理,直到表示式結束
- 如果字元是‘)’,將其入棧
- 如果字元是數字,新增到s2中
- 如果字元是運算子,先將棧頂優先順序不低於該運算子的運算子出棧,新增到s2中,再將該運算子入棧。當‘)’在棧中是,優先順序最低
- 如果字元是‘(’,將棧頂元素出棧,新增到s2中,直到出棧的是‘)’
step3:如果表示式結束,但棧中還有元素,將所有元素出棧,新增s2中
step4:將棧s2中元素依次出棧,即得到字首表示式
給定一個表示式的中綴形式:(4+1*(5-2))-6/3,其字首形式為 - + 4 * 1 - 5 2 / 6 3
表示式的計算
中綴表示式的計算我們已經非常清楚,字首和字尾表示式更適合計算機處理
字尾表示式的計算
字尾表示式沒有括號,運算子的順序即為實際運算順序,在求值過程中,當遇到運算子時,只要取得前兩個運算元就可以立即進行計算。當操作數出現時,不能立即求值,需要先儲存等待運算子。對於等待中的運算元而言,後出現的先運算,所以需要一個棧輔助操作。
字尾表示式的運算過程如下:
step1:設定一個棧
step2:從左到右對字尾表示式中的字元進行以下處理:
- 如果字元是數字,現將其轉化為數字,然後入棧
- 如果字元是運算子,出棧兩個值進行計算。計算結果入棧
- 重複以上步驟,直到字尾表示式掃描結束,棧中最後一個元素就是表示式的結果。
給定字尾表示式4 1 5 2 - * + 6 3 / -,依次將4 1 5 2 入棧,當掃描到-時,2,5出棧,計算5-2=3;將3入棧,此時棧中元素為4 1 3。接著掃描到*,3 1出棧,計算1*3=3,3入棧,棧中元素為4 3,。掃描+,3 4出棧,計算4+3=7,7入棧。接著6 3 入棧,棧中該元素為7 6 3,掃描到/,3 6出棧,計算6/3=2,2入棧,棧中元素為7 2.掃描-,2 7 出棧,計算7-2=5,5入棧。表示式掃描完畢,棧中元素為5,表示式結果為5.
字首表示式的計算
字首表示式的計算掃描順序從右到左,其他和字尾表示式的計算完全一致。