一、算術表示式的中綴表示
把運算子放在參與運算的兩個運算元中間的算術表示式稱為中綴表示式。例如:2+3*4 – 6/9
算術表示式中包含了算術運算子和算術量(常量、變數、函式),而運算子之間又存在著優先順序,不能簡單地進行從左到右運算,編譯程式在求值時,不能簡單從左到右運算,必須先算運算級別高的,再算運算級別低的,同一級運算才從左到右。在計算機中進行中綴表示式求值較麻煩。而字尾表示式求值較方便(無須考慮運算子的優先順序及圓括號)。
二、算術表示式的字尾表示
把運算子放在參與運算的兩個運算元後面的算術表示式稱為字尾表示式。
例如,對於下列各中綴表示式:
(1)3/5+8
(2)18-9*(4+3)
對應的字尾表示式為:
(1)3 5 / 8 +
(2)18 9 4 3 + * -
轉換規則:把每個運算子都移到它的兩個運算元的後面,然後刪除掉所有的括號即可.
例如,將中綴表示式a+b*c-d(e*f)轉換為字尾表示式.
三、字尾表示式的求值
將中綴表示式轉換成等價的字尾表示式後,求值時,不需要再考慮運算子的優先順序,只需從左到右掃瞄一遍字尾表示式即可。具體求值步驟為:從左到右掃瞄字尾表示式,遇到運算子就把表示式中該運算子前面兩個運算元取出並運算,然後把結果帶回字尾表示式;繼續掃瞄直到字尾表示式最後乙個表示式。
例如,字尾表示式(abc*+def*/-)的求值
四、字尾表示式的求值的演算法
設定乙個棧,開始時,棧為空,然後從左到右掃瞄字尾表示式,若遇運算元,則進棧;若遇運算子,則從棧中退出兩個元素,先退出的放到運算子的右邊,後退出的放到運算子左邊,運算後的結果再進棧,直到字尾表示式掃瞄完畢。此時,棧中僅有乙個元素,即為運算的結果。
例,求字尾表示式:1 2 + 8 2 - 7 4 - / *的值,
棧的變化情如下:
步驟棧中元素說明1
11進棧212
2進棧3
遇+號退棧2和143
1+2=3的結果3進棧538
8進棧6
3822進棧73
遇-號退棧2和8836
8-2=6的結果6進棧
9367
7進棧10
3674
4進棧11
36遇-號退棧4和7
1236
7-4=3的結果3進棧133
遇/號退棧3和6
1432
6/3=2的結果2進棧
15遇*號退棧2和3166
3*2=6進棧176
掃瞄完畢,運算結束
從上可知,最後求得的字尾表示式之值為6,與用中綴表示式求得的結果一致,但字尾式求值要簡單得多。
五、中綴表示式變成等價的字尾表示式的演算法
將中綴表示式變成等價的字尾表示式,表示式中運算元次序不變,運算子次序發生變化,同時去掉了圓括號。轉換規則是:設立乙個棧,存放運算子,首先棧為空,編譯程式從左到右掃瞄中綴表示式,若遇到運算元,直接輸出,並輸出乙個空格作為兩個運算元的分隔符;若遇到運算子,則必須與棧頂比較,運算子級別比棧頂級別高則進棧,否則退出棧頂元素並輸出,然後輸出乙個空格作分隔符;若遇到左括號,進棧;若遇到右括號,則一直退棧輸出,直到退到左括號止。當棧變成空時,輸出的結果即為字尾表示式。將中綴表示式(1+2)*((8-2)/(7-4))變成等價的字尾表示式。
現在用棧來實現該運算,棧的變化及輸出結果如下:
步驟棧中元素
輸出結果說明1
((進棧2(
1輸出13(+
1+進棧4(+
1 2輸出2
51 2 +
+退棧輸出,退棧到(止6*
1 2 +
*進棧7
*(1 2 +
(進棧8
*((1 2 +
(進棧9
*((1 2 + 8
輸出810
*((-
1 2 + 8
輸出211
*((-
1 2 + 8 2
- 進棧
12*(
1 2 + 8 2 -
-退棧輸出,退棧到(止
13*(/
1 2 + 8 2 -
/ 進棧
14*(/(
1 2 + 8 2 -
( 進棧
15*(/(
1 2 + 8 2 - 7
輸出716
*(/(-
1 2 + 8 2 - 7
-進棧17
*(/(-
1 2 + 8 2 - 7 4
輸出418
*(-1 2 + 8 2 - 7 4 -
-退棧輸出,退棧到(止19*
1 2 + 8 2 - 7 4 - /
/退棧輸出,退棧到(止
201 2 + 8 2 - 7 4 - / *
*退棧並輸出
1、 數制轉換
將乙個非負的十進位制整數n轉換為另乙個等價的基為b的b進製數的問題,很容易通過"除b取餘法"來解決。
【例】將十進位制數13轉化為二進位制數。
解答:按除2取餘法,得到的餘數依次是1、0、1、1,則十進位制數轉化為二進位制數為1101。
分析:由於最先得到的餘數是轉化結果的最低位,最後得到的餘數是轉化結果的最高位,因此很容易用棧來解決。
轉換演算法如下:
typedef int datatype;//應將順序棧的datatype定義改為整型
void multibaseoutput (int n,int b)
while(!stackempty(&s))
}2、 棧與遞迴
(1) 遞迴
所謂遞迴是指:若在乙個函式、過程或者資料結構定義的內部,直接(或間接)出現定義本身的應用,則稱它們是遞迴的,或者是遞迴定義的。
遞迴是一種強有力的數學工具,它可使問題的描述和求解變得簡潔和清晰。
遞迴演算法常常比非遞迴演算法更易設計,尤其是當問題本身或所涉及的資料結構是遞迴定義的時候,使用遞迴演算法特別合適。
(2)遞迴演算法的設計步驟
第一步驟(遞迴步驟):將規模較大的原問題分解為乙個或多個規模更小、但具有類似於原問題特性的子問題。即較大的問題遞迴地用較小的子問題來描述,解原問題的方法同樣可用來解這些子問題。
第二步驟:確定乙個或多個無須分解、可直接求解的最小子問題(稱為遞迴的終止條件)。
【例】非負整數n的階乘可遞迴定義為:
(3)棧在遞迴演算法的內部實現中所起的作用。
①呼叫函式時:系統將會為呼叫者構造乙個由參數列和返回位址組成的活動記錄,並將其壓入到由系統提供的執行時刻棧的棧頂,然後將程式的控制權轉移到被調函式。若被調函式有區域性變數,則在執行時刻棧的棧頂也要為其分配相應的空間。因此,活動記錄和這些區域性變數形成了乙個可供被調函式使用的活動結構。
字首式變字尾式演算法
字首式的特點:每個操作符後有兩個運算元(可能為運算結果)
演算法思想:從左到右掃瞄字首表示式
1. 操作符進棧(s),同時記錄操作符已接受的運算元數目(count),初值為0
2. 運算元直接寫到乙個buffer中,同時棧頂運算元所對應的count++
while(count==2)
繼續1、2步驟直至字首表示式掃瞄結束。
資料結構:
typedef struct tagstackelem
stackelem;
typedef struct tagstack
演算法:
void transform(char *prefix,char *suffix)
else }}
q=『\0』;
}例項:+++ab+cde
資料結構 棧的應用
要求 首先將運算元棧opnd設為空棧,而將 作為運算子棧opter的棧底元素,這樣的目的是判斷表示式是否求值完畢 2 依次讀入表示式的每個字元,表示式須以 結尾,若是運算元則入棧opnd,若是運算子,則將此運算子c與opter的棧頂元素top比較優先順序後執行相應的操作,具體操作如下 i 若top的...
資料結構 棧的應用
棧是限制插入和刪除只能在乙個位置上進行的表,該位置是表的末端,也叫做棧頂。對棧的操作有進棧和出棧,進棧也叫做插入,出棧也就是刪除最後插入的元素。因此棧也被稱作lifo 後進先出 表。棧通常有兩種實現方式,陣列實現和鍊錶實現。下面是棧的兩個小應用demo 字串逆序 由於棧後進先出的特性,所以棧可以用於...
資料結構 棧的應用
stack.h include include typedef char elemtype typedef struct stackstack,stackptr 初始化棧 void initstack stackptr s 判空 bool stackempty stackptr s 入棧 void ...