文章目錄
1. 棧
1.1 棧的定義
通常,棧可定義爲只允許在表的末端進行插入和刪除的線性表。後進先出(LIFO)
棧的基本操作
- InitStack(&S):初始化一個空棧
- StackEmpty(S):判斷一個棧是否爲空
- Push(&S, x):進棧
- Pop(&S, &x):出棧
- GetTop(S, &x):讀棧頂元素
- DestroyStack(&S):銷燬棧
解答算法題時,若題幹未做出限制,則可直接使用這些基本的操作函數。
1.2 棧的順序和鏈式存儲
P60-P62
1.3 共享棧
利用棧底位置相對不變的特性,可讓兩個順序棧共享一個一維數據空間,將兩個棧的棧底分別設置在共享空間的兩端,兩個棧頂向共享空間的中間延伸。
共享棧是爲了更有效地利用存儲空間,兩個棧的空間互相調節,只有在整個存儲空間被佔滿時才發生上溢。其存取數據的時間複雜度均爲,所以對存取效率沒有什麼影響。
2. 隊列
2.1 隊列的定義
隊列是另一種限定存取位置的線性表,它只允許在表的一端插入,在另一端刪除,允許插入的一端叫做隊尾(rear),允許刪除的一端叫做隊頭(front)。先進先出(FIFO)。
隊列常見基本操作
InitQueue(&Q); //初始化隊列
QueueEmpty(Q); //判斷隊列是否爲空
EnQueue(&Q, x); //入隊
DeQueue(&Q, &x); //出隊
GetHead(Q, &x); //讀隊頭元素
2.2 循環隊列
循環隊列操作
- 初始時:front==rear=0;
- 隊頭指針進1:front=(front+1)%MaxSize;
- 隊尾指針進1:rear=(rear+1)%MaxSize;
- 隊列長度:(rear+MaxSize-front)%MaxSize;
判斷隊空隊滿
用(rear+1)%MaxSize==front 來判斷是否隊已滿,即讓rear指到front前一個位置就認爲隊已滿。所以在隊滿情形實際空了一個元素位置。如果不留這個空位,導致就會混淆隊空隊滿條件。所以,在循環隊列中,最多隻能存放MaxSize-1個元素。
2.3 鏈式隊列
隊列的隊頭指針指向單鏈表的第一個結點,隊尾指針指向單鏈表的最後一個結點。
用單鏈表表示的鏈式隊列特別適合於數據元素變動比較大的情形,而且不存在隊列產生溢出的情況。
2.4 雙端隊列
雙端隊列可以在隊列的兩端進行插入和刪除。有的可能有限制,比如限制輸入(一端輸入,兩端輸出)或限制輸出(一端輸出,兩端輸入)
3. 棧與隊列的應用
3.1 棧在括號匹配中的應用
算法思想如下:
- 初始設置一個空棧,順序讀入括號。
- 若是右括號,則或者使置於棧頂的最急迫期待得以消解,或者是不合法情況(括號序列不匹配,退出程序)。
- 若是左括號,則作爲一個新的更急迫的期待壓入棧中,自然使原有的在棧中的所有未消解的期待的急迫性降了一級。算法結束時,棧爲空,否則括號序列不匹配。
3.2 棧在表達式求值中的應用 P95
任何一個表達式都是由操作數(亦稱運算對象)、操作符(亦稱運算符)和分界符組成。通常,算術表達式有三種表示:
- 中綴(infix)表示:<操作數><操作符><操作數> 例如:A+B
- 前綴(prefix)表示:<操作符><操作數><操作數> 例如:+AB
- 後綴(postfix)表示:<操作數><操作數><操作符> 例如:AB+
由於中綴表示有操作符的優先級問題,還有可加括號改變運算順序的問題,所以對於編譯程序來說,一般不使用中綴表示處理表達式,因爲用後綴表示計算表達式的值只用一個棧,而前綴中綴兩個棧,所以編譯程序一般使用後綴表示求解表達式的值。
利用棧將中綴轉換成後綴
- isp叫棧內優先數
- icp叫棧外優先數
算法見P99
該轉換算法對輸入表達式只進行一次自左向右的掃描,對每個操作數只執行一次輸出,其執行時間爲,對每個操作符,執行進棧和退棧各一次,其時間也爲。若表達式中符號的總數爲n,則總的執行時間複雜度爲。