第三章:棧和隊列
1.棧的應用
1.1括號匹配
我們在數學運算中 [(A+b)*c] - (E-F)
往往都會有[ ]
和 ( )
來表示運算的優先級,我們把這樣的[ ]
和 ( )
提取出來組成的序列叫做括號匹配序列
。
匹配序列
( [ ( ) ] )
[ ] [ ] ( )
( ) [ ( ) ]
上面是正確的可以匹配的序列,每一個(
或者[
都有與之對應的)
或者]
。
不匹配序列
( [ ( ) ]
] [ ] ( )
( ] [ ( ) ]
下面是一個正確匹配的序列,我們給每一個標上號,一次輸入到棧中,判斷闊號是否匹配。
算法思想:
- 1.初始化一個空棧,順序讀入闊號
- 2.若是右闊號,則與棧頂元素進行匹配
-
- 若匹配,則彈出棧頂元素進行下一個元素
-
- 若不匹配,則該序列不合法
- 3.若是左闊號,則壓入棧中
- 4.如果全部元素遍歷完畢,棧中非空則序列不合法
1.2表達式求值
例如:A+B+C-E-F
像這種簡單的表達式求值我們通過遍歷,加上if
判斷就可以解決,但是[(A+B)*C]-(E-F)
這種比較複雜的表達式這就有一些複雜的優先級了。這就需要棧來解決了,下面介紹幾種表達式的分類。
在解決表達式求值的問題我們通常要將中綴表達式
轉成前綴表達式
或者轉成後綴表達式
,不過最常用的還是轉成後綴表達式
。常常用後綴表達式計算表達式的值。
1.3中綴表達式轉前&後綴
中綴轉前綴&後綴
[(A+B)*C]-(E-F)
我們按照運算的優先級首先計算(A+B)講它轉成前綴:+AB,[+AB*C]-(E-F)
接着乘以C轉成前綴爲:* +ABC,這樣第一個方括號的轉換完畢,接着按照運算優先級,將[E-F]轉成前綴:-EF,現在表達式爲:* +ABC-(-EF)
,接着將中間的-
提到最前面得:-*+ABC-EF
前綴表達式:- * + A B C - E F
過程和上面得過程相同,只不過將運算符號號放後面就行。
後綴表達式:A B + C * E F - -
使用棧將中綴轉後綴得算法思想:
( ( A + B ) * C ) - ( E - F )
- 數字直接加入後綴表達式
- 運算符時:
- a.若爲
(
,入棧;.b - b.若爲’
)
,則依次把棧中的運算符加入後綴表達式,直到出現(
,並從棧中刪除(
- c.若爲
+
,-
,*
,/
-
- 1.棧空,入棧;
-
- 2.棧頂元素爲
(
,入棧;
- 2.棧頂元素爲
-
- 3.高於棧頂元素優先級,入棧;·
-
- 4.否則,依次彈出棧頂運算符,直到一個優先級比它低的運算符或
(
爲止;`
- 4.否則,依次彈出棧頂運算符,直到一個優先級比它低的運算符或
- d.遍歷完成,若棧非空依次彈出所有元素。
使用此思想執行一遍將表達式裝成後綴:
爲了方便文字描述,定義一個H
作爲後綴表達式,定義一個Z
棧。
首先( (
依次入棧(規則:a),此時Z=( (
,接着數字A,直接加入後綴表達式中此時H=A
接着+
入棧(規則:c 2),此時Z=*((+
接着B直接加入後綴表達式中:H=AB
,接着)
入棧符合規則b,則此時Z=(
,H=AB+
,接着*
入棧,Z=(*
,接着)
入棧符合規則b,則此時Z=空
,H=AB+C*
,接着-(
依次入棧,此時Z=-(
,接着E
,直接加入後綴表達式:H=AB+C*E
,接着-
入棧,此時Z=-(-
接着F直接加入後綴表達式中,H=AB+C*EF
,接着)
入棧符合規則b,則此時z=-
,H=AB+C*EF-
,然後符合規則d,此時z=空
,H=AB+C*EF- -
。
2.遞歸
遞歸 若在一個函數、過程或數據結構的定義中又應用了它自身,則稱它爲遞歸定義的,簡稱遞歸
常見得遞歸例子:
斐波那契數列:0,1,1,2,3,5…
此數列從第三項開始每一項等於前兩項得和。
使用C實現該遞歸過程
int Fib(int n){//n是第幾個斐波那契數
if(n==0){
return 0;
}else if(n==1){
return 1;
}else if(){
return Fib(n-1)+Fib(n-2);
}
}
遞歸得精髓在於能否將原始問題轉換爲屬性相同但規模較小的問題。
2.1遞歸產生的問題
- 在遞歸調用過程中,系統爲每一層的返回點、局部變量、傳入實參等開闢了遞歸工作棧來進行數據存儲,遞歸次數過多容易造成棧溢出。
- 通常情況下遞歸的效率並不高
比如上述的斐波那契數列函數,假如我們傳入5
,則整個過程爲:
我們會發現,這當中我們發現一些相同結果我們會重複調用很多遍,這樣的重複調用會造成遞歸的效率不高的問題。
在遞歸算法轉換成非遞歸算法時,往往需要藉助棧來進行。
理木客
歡迎關注公衆號理木客
,堅持原創知識分享,更多精彩等你發現,期待你的關注