Chapter 3 棧與隊列

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 共享棧

利用棧底位置相對不變的特性,可讓兩個順序棧共享一個一維數據空間,將兩個棧的棧底分別設置在共享空間的兩端,兩個棧頂向共享空間的中間延伸。

共享棧是爲了更有效地利用存儲空間,兩個棧的空間互相調節,只有在整個存儲空間被佔滿時才發生上溢。其存取數據的時間複雜度均爲O(1)O(1),所以對存取效率沒有什麼影響。

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前一個位置就認爲隊已滿。所以在隊滿情形實際空了一個元素位置。如果不留這個空位,導致rear==frontrear==front就會混淆隊空隊滿條件。所以,在循環隊列中,最多隻能存放MaxSize-1個元素

2.3 鏈式隊列

隊列的隊頭指針指向單鏈表的第一個結點,隊尾指針指向單鏈表的最後一個結點。
用單鏈表表示的鏈式隊列特別適合於數據元素變動比較大的情形,而且不存在隊列產生溢出的情況。

2.4 雙端隊列

雙端隊列可以在隊列的兩端進行插入和刪除。有的可能有限制,比如限制輸入(一端輸入,兩端輸出)或限制輸出(一端輸出,兩端輸入)

3. 棧與隊列的應用


3.1 棧在括號匹配中的應用

算法思想如下:

  1. 初始設置一個空棧,順序讀入括號。
  2. 若是右括號,則或者使置於棧頂的最急迫期待得以消解,或者是不合法情況(括號序列不匹配,退出程序)。
  3. 若是左括號,則作爲一個新的更急迫的期待壓入棧中,自然使原有的在棧中的所有未消解的期待的急迫性降了一級。算法結束時,棧爲空,否則括號序列不匹配。

3.2 棧在表達式求值中的應用 P95

任何一個表達式都是由操作數(亦稱運算對象)、操作符(亦稱運算符)和分界符組成。通常,算術表達式有三種表示:

  • 中綴(infix)表示:<操作數><操作符><操作數> 例如:A+B
  • 前綴(prefix)表示:<操作符><操作數><操作數> 例如:+AB
  • 後綴(postfix)表示:<操作數><操作數><操作符> 例如:AB+

由於中綴表示有操作符的優先級問題,還有可加括號改變運算順序的問題,所以對於編譯程序來說,一般不使用中綴表示處理表達式,因爲用後綴表示計算表達式的值只用一個棧,而前綴中綴兩個棧,所以編譯程序一般使用後綴表示求解表達式的值

利用棧將中綴轉換成後綴

  • isp叫棧內優先數
  • icp叫棧外優先數

算法見P99

該轉換算法對輸入表達式只進行一次自左向右的掃描,對每個操作數只執行一次輸出,其執行時間爲O(1)O(1),對每個操作符,執行進棧和退棧各一次,其時間也爲O(1)O(1)。若表達式中符號的總數爲n,則總的執行時間複雜度爲O(n)O(n)

3.3 棧在遞歸中的應用

3.4 隊列在層次遍歷中的應用

3.5 隊列在計算機系統中的應用

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